diff options
Diffstat (limited to 'src')
312 files changed, 14650 insertions, 3126 deletions
diff --git a/src/3rdparty b/src/3rdparty -Subproject 111349f18a4d352d40c1c106a6f8e98a9f84389 +Subproject 0240cfc1a59deb5b612923d47ccef72f10504fe diff --git a/src/buildtools/gn.pro b/src/buildtools/gn.pro index 559cdf183..b6bf9cfc4 100644 --- a/src/buildtools/gn.pro +++ b/src/buildtools/gn.pro @@ -18,7 +18,17 @@ build_pass|!debug_and_release { src_3rd_party_dir = $$absolute_path("$${getChromiumSrcDir()}/../", "$$QTWEBENGINE_ROOT") gn_bootstrap = $$system_path($$absolute_path(gn/build/gen.py, $$src_3rd_party_dir)) - gn_configure = $$system_quote($$gn_bootstrap) --no-last-commit-position --out-path $$out_path + gn_gen_args = --no-last-commit-position --out-path $$out_path \ + --cc \"$$which($$QMAKE_CC)\" --cxx \"$$which($$QMAKE_CXX)\" \ + --ld \"$$which($$QMAKE_LINK)\" + + msvc:!clang_cl: gn_gen_args += --use-lto + + gn_configure = $$system_quote($$gn_bootstrap) $$gn_gen_args + macos { + gn_configure += --isysroot \"$$QMAKE_MAC_SDK_PATH\" + } + message($$gn_configure) !system("$$pythonPathForSystem() $$gn_configure") { error("GN generation error!") } diff --git a/src/core/accessibility_activation_observer.cpp b/src/core/accessibility_activation_observer.cpp new file mode 100644 index 000000000..75ad90c54 --- /dev/null +++ b/src/core/accessibility_activation_observer.cpp @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "accessibility_activation_observer.h" + +#ifndef QT_NO_ACCESSIBILITY + +#include "content/browser/accessibility/browser_accessibility_state_impl.h" + +namespace QtWebEngineCore { + +namespace { + +bool isAccessibilityEnabled() { + // On Linux accessibility is disabled by default due to performance issues, + // and can be re-enabled by setting the QTWEBENGINE_ENABLE_LINUX_ACCESSIBILITY environment + // variable. For details, see QTBUG-59922. +#ifdef Q_OS_LINUX + static bool accessibility_enabled + = qEnvironmentVariableIsSet("QTWEBENGINE_ENABLE_LINUX_ACCESSIBILITY"); +#else + const bool accessibility_enabled = true; +#endif + return accessibility_enabled; +} + +} // namespace + +AccessibilityActivationObserver::AccessibilityActivationObserver() +{ + if (isAccessibilityEnabled()) { + QAccessible::installActivationObserver(this); + if (QAccessible::isActive()) + content::BrowserAccessibilityStateImpl::GetInstance()->EnableAccessibility(); + } +} + +AccessibilityActivationObserver::~AccessibilityActivationObserver() +{ + QAccessible::removeActivationObserver(this); +} + +void AccessibilityActivationObserver::accessibilityActiveChanged(bool active) +{ + if (active) + content::BrowserAccessibilityStateImpl::GetInstance()->EnableAccessibility(); + else + content::BrowserAccessibilityStateImpl::GetInstance()->DisableAccessibility(); +} + +} // namespace QtWebEngineCore + +#endif // QT_NO_ACCESSIBILITY diff --git a/src/core/net/qrc_protocol_handler_qt.cpp b/src/core/accessibility_activation_observer.h index eb716f182..e42c83eb5 100644 --- a/src/core/net/qrc_protocol_handler_qt.cpp +++ b/src/core/accessibility_activation_observer.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtWebEngine module of the Qt Toolkit. @@ -37,27 +37,27 @@ ** ****************************************************************************/ -#include "qrc_protocol_handler_qt.h" -#include "url_request_qrc_job_qt.h" +#ifndef ACCESSIBILITY_ACTIVATION_OBSERVER_H +#define ACCESSIBILITY_ACTIVATION_OBSERVER_H -#include "net/base/net_errors.h" -#include "net/url_request/url_request.h" -#include "net/url_request/url_request_error_job.h" +#ifndef QT_NO_ACCESSIBILITY +#include <QtGui/qaccessible.h> namespace QtWebEngineCore { -const char kQrcSchemeQt[] = "qrc"; +class RenderWidgetHostViewQt; -QrcProtocolHandlerQt::QrcProtocolHandlerQt() +class AccessibilityActivationObserver : public QAccessible::ActivationObserver { -} +public: + AccessibilityActivationObserver(); + ~AccessibilityActivationObserver(); -net::URLRequestJob *QrcProtocolHandlerQt::MaybeCreateJob(net::URLRequest *request, net::NetworkDelegate *networkDelegate) const -{ - if (!networkDelegate) - return new net::URLRequestErrorJob(request, Q_NULLPTR, net::ERR_ACCESS_DENIED); - - return new URLRequestQrcJobQt(request, networkDelegate); -} + void accessibilityActiveChanged(bool active) override; +}; } // namespace QtWebEngineCore + +#endif // QT_NO_ACCESSIBILITY + +#endif // ACCESSIBILITY_ACTIVATION_OBSERVER_H diff --git a/src/core/accessibility_tree_formatter_qt.cpp b/src/core/accessibility_tree_formatter_qt.cpp index 8b15c5dee..706857207 100644 --- a/src/core/accessibility_tree_formatter_qt.cpp +++ b/src/core/accessibility_tree_formatter_qt.cpp @@ -201,10 +201,10 @@ const std::string AccessibilityTreeFormatterQt::GetDenyString() #endif // QT_NO_ACCESSIBILITY // static -AccessibilityTreeFormatter* AccessibilityTreeFormatter::Create() +std::unique_ptr<AccessibilityTreeFormatter> AccessibilityTreeFormatter::Create() { #ifndef QT_NO_ACCESSIBILITY - return new AccessibilityTreeFormatterQt(); + return std::unique_ptr<AccessibilityTreeFormatter>(new AccessibilityTreeFormatterQt()); #else return nullptr; #endif diff --git a/src/core/api/core_api.pro b/src/core/api/core_api.pro index 4b69b348a..326d4481f 100644 --- a/src/core/api/core_api.pro +++ b/src/core/api/core_api.pro @@ -32,12 +32,14 @@ gcc: QMAKE_CXXFLAGS_WARN_ON = -Wno-unused-parameter HEADERS = \ qwebenginecallback.h \ qwebenginecallback_p.h \ + qwebengineclientcertificatestore.h \ qtwebenginecoreglobal.h \ qtwebenginecoreglobal_p.h \ qwebenginecookiestore.h \ qwebenginecookiestore_p.h \ qwebenginehttprequest.h \ qwebenginemessagepumpscheduler_p.h \ + qwebenginenotification.h \ qwebenginequotarequest.h \ qwebengineregisterprotocolhandlerrequest.h \ qwebengineurlrequestinterceptor.h \ @@ -49,9 +51,11 @@ HEADERS = \ SOURCES = \ qtwebenginecoreglobal.cpp \ + qwebengineclientcertificatestore.cpp \ qwebenginecookiestore.cpp \ qwebenginehttprequest.cpp \ qwebenginemessagepumpscheduler.cpp \ + qwebenginenotification.cpp \ qwebenginequotarequest.cpp \ qwebengineregisterprotocolhandlerrequest.cpp \ qwebengineurlrequestinfo.cpp \ diff --git a/src/core/api/qtwebenginecoreglobal.cpp b/src/core/api/qtwebenginecoreglobal.cpp index 5a634641b..25d0bd3be 100644 --- a/src/core/api/qtwebenginecoreglobal.cpp +++ b/src/core/api/qtwebenginecoreglobal.cpp @@ -58,7 +58,8 @@ QT_END_NAMESPACE #ifndef QT_NO_OPENGL #ifdef Q_OS_MACOS -static bool needsOfflineRendererWorkaround() { +static bool needsOfflineRendererWorkaround() +{ size_t hwmodelsize = 0; if (sysctlbyname("hw.model", nullptr, &hwmodelsize, nullptr, 0) == -1) @@ -91,7 +92,7 @@ static void deleteShareContext() // after the QGuiApplication creation, when AA_ShareOpenGLContexts fills // the same need but the flag has to be set earlier. -QWEBENGINECORE_PRIVATE_EXPORT void initialize() +Q_WEBENGINECORE_PRIVATE_EXPORT void initialize() { #ifndef QT_NO_OPENGL #ifdef Q_OS_WIN32 @@ -133,4 +134,3 @@ QWEBENGINECORE_PRIVATE_EXPORT void initialize() #endif // QT_NO_OPENGL } } // namespace QtWebEngineCore - diff --git a/src/core/api/qtwebenginecoreglobal.h b/src/core/api/qtwebenginecoreglobal.h index bcff622b7..c425d1478 100644 --- a/src/core/api/qtwebenginecoreglobal.h +++ b/src/core/api/qtwebenginecoreglobal.h @@ -46,9 +46,9 @@ QT_BEGIN_NAMESPACE #if defined(BUILDING_CHROMIUM) -# define QWEBENGINECORE_EXPORT Q_DECL_EXPORT +# define Q_WEBENGINECORE_EXPORT Q_DECL_EXPORT #else -# define QWEBENGINECORE_EXPORT Q_DECL_IMPORT +# define Q_WEBENGINECORE_EXPORT Q_DECL_IMPORT #endif #define ASSERT_ENUMS_MATCH(A, B) Q_STATIC_ASSERT_X(static_cast<int>(A) == static_cast<int>(B), "The enum values must match"); diff --git a/src/core/api/qtwebenginecoreglobal_p.h b/src/core/api/qtwebenginecoreglobal_p.h index 27bf2d9f9..655b2a814 100644 --- a/src/core/api/qtwebenginecoreglobal_p.h +++ b/src/core/api/qtwebenginecoreglobal_p.h @@ -63,6 +63,6 @@ #define QT_NOT_USED Q_UNREACHABLE(); // This will assert in debug. #endif -#define QWEBENGINECORE_PRIVATE_EXPORT QWEBENGINECORE_EXPORT +#define Q_WEBENGINECORE_PRIVATE_EXPORT Q_WEBENGINECORE_EXPORT #endif // QTWEBENGINECOREGLOBAL_P_H diff --git a/src/core/api/qwebenginecallback.h b/src/core/api/qwebenginecallback.h index b981b2afb..49efc50b2 100644 --- a/src/core/api/qwebenginecallback.h +++ b/src/core/api/qwebenginecallback.h @@ -54,7 +54,7 @@ QT_BEGIN_NAMESPACE namespace QtWebEnginePrivate { -template <typename T> +template<typename T> class QWebEngineCallbackPrivateBase : public QSharedData { public: QWebEngineCallbackPrivateBase() {} @@ -62,32 +62,32 @@ public: virtual void operator()(T) = 0; }; -template <typename T, typename F> +template<typename T, typename F> class QWebEngineCallbackPrivate : public QWebEngineCallbackPrivateBase<T> { public: - QWebEngineCallbackPrivate(F callable) - : m_callable(callable) - {} + QWebEngineCallbackPrivate(F callable) : m_callable(callable) {} void operator()(T value) override { m_callable(value); } + private: F m_callable; }; } // namespace QtWebEnginePrivate -template <typename T> +template<typename T> class QWebEngineCallback { public: - template <typename F> + template<typename F> QWebEngineCallback(F f) : d(new QtWebEnginePrivate::QWebEngineCallbackPrivate<T, F>(f)) - { } - QWebEngineCallback() { } + {} + QWebEngineCallback() {} void swap(QWebEngineCallback &other) Q_DECL_NOTHROW { qSwap(d, other.d); } operator bool() const { return d; } + private: friend class QtWebEngineCore::CallbackDirectory; - QExplicitlySharedDataPointer<QtWebEnginePrivate::QWebEngineCallbackPrivateBase<T> > d; + QExplicitlySharedDataPointer<QtWebEnginePrivate::QWebEngineCallbackPrivateBase<T>> d; }; Q_DECLARE_SHARED(QWebEngineCallback<int>) diff --git a/src/core/api/qwebenginecallback_p.h b/src/core/api/qwebenginecallback_p.h index 24b4495df..133a86f6d 100644 --- a/src/core/api/qwebenginecallback_p.h +++ b/src/core/api/qwebenginecallback_p.h @@ -62,11 +62,11 @@ #include <type_traits> // keep in sync with Q_DECLARE_SHARED... in qwebenginecallback.h -#define FOR_EACH_TYPE(F) \ - F(bool) \ - F(int) \ - F(const QString &) \ - F(const QByteArray &) \ +#define FOR_EACH_TYPE(F) \ + F(bool) \ + F(int) \ + F(const QString &) \ + F(const QByteArray &) \ F(const QVariant &) namespace QtWebEngineCore { @@ -82,7 +82,7 @@ public: { // "Cancel" pending callbacks by calling them with an invalid value. // This guarantees that each callback is called exactly once. - for (CallbackSharedDataPointerBase * const sharedPtrBase: m_callbackMap) { + for (CallbackSharedDataPointerBase *const sharedPtrBase : m_callbackMap) { Q_ASSERT(sharedPtrBase); sharedPtrBase->invokeEmpty(); delete sharedPtrBase; @@ -106,20 +106,18 @@ public: template<typename T> void invokeEmpty(const QWebEngineCallback<T> &callback); -#define DEFINE_INVOKE_FOR_TYPE(Type) \ - void invoke(quint64 callbackId, Type result) { \ - invokeInternal<Type>(callbackId, std::forward<Type>(result)); \ - } +#define DEFINE_INVOKE_FOR_TYPE(Type) \ + void invoke(quint64 callbackId, Type result) { invokeInternal<Type>(callbackId, std::forward<Type>(result)); } FOR_EACH_TYPE(DEFINE_INVOKE_FOR_TYPE) #undef DEFINE_INVOKE_FOR_TYPE - template <typename A> + template<typename A> void invokeDirectly(const QWebEngineCallback<typename std::remove_reference<A>::type &> &callback, A &argument) { return callback.d.data()->operator()(argument); } - template <typename A> + template<typename A> void invokeDirectly(const QWebEngineCallback<typename std::remove_reference<A>::type> &callback, const A &argument) { return callback.d.data()->operator()(std::forward<const A &>(argument)); @@ -127,39 +125,45 @@ public: private: struct CallbackSharedDataPointerBase { - virtual ~CallbackSharedDataPointerBase() { } + virtual ~CallbackSharedDataPointerBase() {} virtual void invokeEmpty() = 0; virtual void doRef() = 0; virtual void doDeref() = 0; - virtual operator bool () const = 0; + virtual operator bool() const = 0; }; - template <typename T> + template<typename T> struct CallbackSharedDataPointer : public CallbackSharedDataPointerBase { - CallbackDirectory* parent; + CallbackDirectory *parent; QtWebEnginePrivate::QWebEngineCallbackPrivateBase<T> *callback; ~CallbackSharedDataPointer() { doDeref(); } - CallbackSharedDataPointer() : parent(0), callback(0) { } + CallbackSharedDataPointer() : parent(0), callback(0) {} CallbackSharedDataPointer(const CallbackSharedDataPointer<T> &other) - : parent(other.parent), callback(other.callback) { doRef(); } + : parent(other.parent), callback(other.callback) + { + doRef(); + } CallbackSharedDataPointer(CallbackDirectory *p, QtWebEnginePrivate::QWebEngineCallbackPrivateBase<T> *c) - : parent(p), callback(c) { Q_ASSERT(callback); doRef(); } + : parent(p), callback(c) + { + Q_ASSERT(callback); + doRef(); + } void invokeEmpty() override; - operator bool () const override { return callback; } + operator bool() const override { return callback; } private: void doRef() override; void doDeref() override; }; - QHash<quint64, CallbackSharedDataPointerBase*> m_callbackMap; + QHash<quint64, CallbackSharedDataPointerBase *> m_callbackMap; }; template<typename T> -inline -void CallbackDirectory::registerCallback(quint64 callbackId, const QWebEngineCallback<T> &callback) +inline void CallbackDirectory::registerCallback(quint64 callbackId, const QWebEngineCallback<T> &callback) { if (!callback.d) return; @@ -167,10 +171,9 @@ void CallbackDirectory::registerCallback(quint64 callbackId, const QWebEngineCal } template<typename T> -inline -void CallbackDirectory::invokeInternal(quint64 callbackId, T result) +inline void CallbackDirectory::invokeInternal(quint64 callbackId, T result) { - CallbackSharedDataPointerBase * const sharedPtrBase = m_callbackMap.take(callbackId); + CallbackSharedDataPointerBase *const sharedPtrBase = m_callbackMap.take(callbackId); if (!sharedPtrBase) return; @@ -181,8 +184,7 @@ void CallbackDirectory::invokeInternal(quint64 callbackId, T result) } template<typename T> -inline -void CallbackDirectory::invokeEmptyInternal(QtWebEnginePrivate::QWebEngineCallbackPrivateBase<T> *callback) +inline void CallbackDirectory::invokeEmptyInternal(QtWebEnginePrivate::QWebEngineCallbackPrivateBase<T> *callback) { Q_ASSERT(callback); using NoRefT = typename std::remove_reference<T>::type; @@ -192,24 +194,21 @@ void CallbackDirectory::invokeEmptyInternal(QtWebEnginePrivate::QWebEngineCallba } template<> -inline -void CallbackDirectory::invokeEmptyInternal(QtWebEnginePrivate::QWebEngineCallbackPrivateBase<bool> *callback) +inline void CallbackDirectory::invokeEmptyInternal(QtWebEnginePrivate::QWebEngineCallbackPrivateBase<bool> *callback) { Q_ASSERT(callback); (*callback)(false); } template<> -inline -void CallbackDirectory::invokeEmptyInternal(QtWebEnginePrivate::QWebEngineCallbackPrivateBase<int> *callback) +inline void CallbackDirectory::invokeEmptyInternal(QtWebEnginePrivate::QWebEngineCallbackPrivateBase<int> *callback) { Q_ASSERT(callback); (*callback)(0); } template<typename T> -inline -void CallbackDirectory::invokeEmpty(const QWebEngineCallback<T> &callback) +inline void CallbackDirectory::invokeEmpty(const QWebEngineCallback<T> &callback) { if (!callback.d) return; @@ -217,9 +216,8 @@ void CallbackDirectory::invokeEmpty(const QWebEngineCallback<T> &callback) invokeEmptyInternal(callback.d.data()); } -template <typename T> -inline -void CallbackDirectory::CallbackSharedDataPointer<T>::doRef() +template<typename T> +inline void CallbackDirectory::CallbackSharedDataPointer<T>::doRef() { if (!callback) return; @@ -227,9 +225,8 @@ void CallbackDirectory::CallbackSharedDataPointer<T>::doRef() callback->ref.ref(); } -template <typename T> -inline -void CallbackDirectory::CallbackSharedDataPointer<T>::doDeref() +template<typename T> +inline void CallbackDirectory::CallbackSharedDataPointer<T>::doDeref() { if (!callback) return; @@ -237,9 +234,8 @@ void CallbackDirectory::CallbackSharedDataPointer<T>::doDeref() delete callback; } -template <typename T> -inline -void CallbackDirectory::CallbackSharedDataPointer<T>::invokeEmpty() +template<typename T> +inline void CallbackDirectory::CallbackSharedDataPointer<T>::invokeEmpty() { if (!callback) return; @@ -248,8 +244,7 @@ void CallbackDirectory::CallbackSharedDataPointer<T>::invokeEmpty() parent->invokeEmptyInternal(callback); } -#define CHECK_RELOCATABLE(x) \ - Q_STATIC_ASSERT((QTypeInfoQuery<QWebEngineCallback< x > >::isRelocatable)); +#define CHECK_RELOCATABLE(x) Q_STATIC_ASSERT((QTypeInfoQuery<QWebEngineCallback<x>>::isRelocatable)); FOR_EACH_TYPE(CHECK_RELOCATABLE) #undef CHECK_RELOCATABLE diff --git a/src/core/api/qwebengineclientcertificatestore.cpp b/src/core/api/qwebengineclientcertificatestore.cpp new file mode 100644 index 000000000..84f273328 --- /dev/null +++ b/src/core/api/qwebengineclientcertificatestore.cpp @@ -0,0 +1,120 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwebengineclientcertificatestore.h" + +#include "net/client_cert_store_data.h" + +#include <QByteArray> +#include <QList> + +QT_BEGIN_NAMESPACE + +#if QT_CONFIG(ssl) + +/*! + \class QWebEngineClientCertificateStore + \inmodule QtWebEngineCore + \since 5.13 + \brief The QWebEngineClientCertificateStore class provides an in-memory store for client certificates. + + The class allows to store client certificates in an in-memory store. + When a web site requests an SSL client certificate, the QWebEnginePage::selectClientCertificate + signal is emitted with matching certificates from the native certificate store or the in-memory store. + The getInstance() method can be used to access the single instance of the class. +*/ + +QWebEngineClientCertificateStore::QWebEngineClientCertificateStore(QtWebEngineCore::ClientCertificateStoreData *storeData) + : m_storeData(storeData) +{} + +/*! + Destroys this QWebEngineClientCertificateStore object. +*/ + +QWebEngineClientCertificateStore::~QWebEngineClientCertificateStore() +{ + // Just in case user has not deleted in-memory certificates + clear(); +} + +/*! + Adds a \a certificate with the \a privateKey to the in-memory client certificate store. +*/ + +void QWebEngineClientCertificateStore::add(const QSslCertificate &certificate, const QSslKey &privateKey) +{ + m_storeData->add(certificate, privateKey); +} + +/*! + Returns a list of the client certificates in the in-memory store. + Returns an empty list if the store does not contain any certificates. +*/ + +QVector<QSslCertificate> QWebEngineClientCertificateStore::certificates() const +{ + QVector<QSslCertificate> certificateList; + for (auto data : qAsConst(m_storeData->extraCerts)) + certificateList.append(data->certificate); + return certificateList; +} + +/*! + Deletes all the instances of the client certificate in the in-memory client certificate store + that matches the certificate \a certificate. +*/ + +void QWebEngineClientCertificateStore::remove(const QSslCertificate &certificate) +{ + m_storeData->remove(certificate); +} + +/*! + Clears all the client certificates from the in-memory store. +*/ + +void QWebEngineClientCertificateStore::clear() +{ + m_storeData->clear(); +} + +#endif // QT_CONFIG(ssl) + +QT_END_NAMESPACE diff --git a/src/core/api/qwebengineclientcertificatestore.h b/src/core/api/qwebengineclientcertificatestore.h new file mode 100644 index 000000000..a4c83bb2e --- /dev/null +++ b/src/core/api/qwebengineclientcertificatestore.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWEBENGINECLIENTCERTIFICATESTORE_H +#define QWEBENGINECLIENTCERTIFICATESTORE_H + +#include <QtWebEngineCore/qtwebenginecoreglobal.h> + +#include <QtCore/qvector.h> +#include <QtNetwork/qsslcertificate.h> +#include <QtNetwork/qsslkey.h> + +namespace QtWebEngineCore { +struct ClientCertificateStoreData; +class ProfileAdapter; +} // namespace QtWebEngineCore + +QT_BEGIN_NAMESPACE + +#if QT_CONFIG(ssl) + +class Q_WEBENGINECORE_EXPORT QWebEngineClientCertificateStore { + +public: + void add(const QSslCertificate &certificate, const QSslKey &privateKey); + QVector<QSslCertificate> certificates() const; + void remove(const QSslCertificate &certificate); + void clear(); + +private: + friend class QtWebEngineCore::ProfileAdapter; + Q_DISABLE_COPY(QWebEngineClientCertificateStore) + + QWebEngineClientCertificateStore(QtWebEngineCore::ClientCertificateStoreData *storeData); + ~QWebEngineClientCertificateStore(); + QtWebEngineCore::ClientCertificateStoreData *m_storeData; +}; + +#endif // QT_CONFIG(ssl) + +QT_END_NAMESPACE + +#endif // QWebEngineClientCertificateStore_H diff --git a/src/core/api/qwebenginecookiestore.cpp b/src/core/api/qwebenginecookiestore.cpp index 3897fb128..40594b9c0 100644 --- a/src/core/api/qwebenginecookiestore.cpp +++ b/src/core/api/qwebenginecookiestore.cpp @@ -47,15 +47,14 @@ #include <QByteArray> #include <QUrl> - namespace { -inline GURL toGurl(const QUrl& url) +inline GURL toGurl(const QUrl &url) { return GURL(url.toString().toStdString()); } -} +} // namespace QT_BEGIN_NAMESPACE @@ -68,8 +67,7 @@ QWebEngineCookieStorePrivate::QWebEngineCookieStorePrivate(QWebEngineCookieStore , m_deleteAllCookiesPending(false) , m_getAllCookiesPending(false) , delegate(0) -{ -} +{} void QWebEngineCookieStorePrivate::processPendingUserCookies() { @@ -112,7 +110,8 @@ void QWebEngineCookieStorePrivate::rejectPendingUserCookies() m_pendingUserCookies.clear(); } -void QWebEngineCookieStorePrivate::setCookie(const QWebEngineCallback<bool> &callback, const QNetworkCookie &cookie, const QUrl &origin) +void QWebEngineCookieStorePrivate::setCookie(const QWebEngineCallback<bool> &callback, const QNetworkCookie &cookie, + const QUrl &origin) { const quint64 currentCallbackId = callback ? m_nextCallbackId++ : static_cast<quint64>(CallbackDirectory::NoCallbackId); @@ -201,7 +200,7 @@ bool QWebEngineCookieStorePrivate::canAccessCookies(const QUrl &firstPartyUrl, c toGurl(firstPartyUrl), net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES); - QWebEngineCookieStore::FilterRequest request = { firstPartyUrl, url, thirdParty, false, 0}; + QWebEngineCookieStore::FilterRequest request = { firstPartyUrl, url, thirdParty, false, 0 }; return filterCallback(request); } @@ -249,10 +248,7 @@ QWebEngineCookieStore::QWebEngineCookieStore(QObject *parent) Destroys this QWebEngineCookieStore object. */ -QWebEngineCookieStore::~QWebEngineCookieStore() -{ - -} +QWebEngineCookieStore::~QWebEngineCookieStore() {} /*! Adds \a cookie to the cookie store. @@ -298,7 +294,8 @@ void QWebEngineCookieStore::loadAllCookies() //TODO: use callbacks or delete dummy ones if (d_ptr->m_getAllCookiesPending) return; - d_ptr->callbackDirectory.registerCallback(CallbackDirectory::GetAllCookiesCallbackId, QWebEngineCallback<const QByteArray&>()); + d_ptr->callbackDirectory.registerCallback(CallbackDirectory::GetAllCookiesCallbackId, + QWebEngineCallback<const QByteArray &>()); //this will trigger cookieAdded signal d_ptr->getAllCookies(); } diff --git a/src/core/api/qwebenginecookiestore.h b/src/core/api/qwebenginecookiestore.h index 89e72dfb0..3d313ac23 100644 --- a/src/core/api/qwebenginecookiestore.h +++ b/src/core/api/qwebenginecookiestore.h @@ -52,12 +52,12 @@ namespace QtWebEngineCore { class ProfileAdapter; class CookieMonsterDelegateQt; -} +} // namespace QtWebEngineCore QT_BEGIN_NAMESPACE class QWebEngineCookieStorePrivate; -class QWEBENGINECORE_EXPORT QWebEngineCookieStore : public QObject { +class Q_WEBENGINECORE_EXPORT QWebEngineCookieStore : public QObject { Q_OBJECT public: @@ -93,6 +93,6 @@ private: QT_END_NAMESPACE -Q_DECLARE_METATYPE(QWebEngineCookieStore*) +Q_DECLARE_METATYPE(QWebEngineCookieStore *) #endif // QWEBENGINECOOKIESTORE_H diff --git a/src/core/api/qwebenginecookiestore_p.h b/src/core/api/qwebenginecookiestore_p.h index 93198d8ed..a79e2b095 100644 --- a/src/core/api/qwebenginecookiestore_p.h +++ b/src/core/api/qwebenginecookiestore_p.h @@ -66,8 +66,7 @@ class CookieMonsterDelegateQt; QT_BEGIN_NAMESPACE -class QWEBENGINECORE_PRIVATE_EXPORT QWebEngineCookieStorePrivate -{ +class Q_WEBENGINECORE_PRIVATE_EXPORT QWebEngineCookieStorePrivate { Q_DECLARE_PUBLIC(QWebEngineCookieStore) struct CookieData { quint64 callbackId; @@ -76,9 +75,10 @@ class QWEBENGINECORE_PRIVATE_EXPORT QWebEngineCookieStorePrivate }; friend class QTypeInfo<CookieData>; QWebEngineCookieStore *q_ptr; + public: QtWebEngineCore::CallbackDirectory callbackDirectory; - std::function<bool(const QWebEngineCookieStore::FilterRequest&)> filterCallback; + std::function<bool(const QWebEngineCookieStore::FilterRequest &)> filterCallback; QVector<CookieData> m_pendingUserCookies; quint64 m_nextCallbackId; bool m_deleteSessionCookiesPending; diff --git a/src/core/api/qwebenginehttprequest.cpp b/src/core/api/qwebenginehttprequest.cpp index b64af4466..3395cc99f 100644 --- a/src/core/api/qwebenginehttprequest.cpp +++ b/src/core/api/qwebenginehttprequest.cpp @@ -67,8 +67,7 @@ QT_BEGIN_NAMESPACE \value Post The POST method. */ -class QWebEngineHttpRequestPrivate : public QSharedData -{ +class QWebEngineHttpRequestPrivate : public QSharedData { public: QUrl url; QWebEngineHttpRequest::Method method; @@ -77,23 +76,18 @@ public: Headers headers; QByteArray postData; - inline QWebEngineHttpRequestPrivate() - { - } + QWebEngineHttpRequestPrivate() {} - ~QWebEngineHttpRequestPrivate() - { - } + ~QWebEngineHttpRequestPrivate() {} - QWebEngineHttpRequestPrivate(const QWebEngineHttpRequestPrivate &other) - : QSharedData(other) + QWebEngineHttpRequestPrivate(const QWebEngineHttpRequestPrivate &other) : QSharedData(other) { method = other.method; url = other.url; headers = other.headers; } - inline bool operator==(const QWebEngineHttpRequestPrivate &other) const + bool operator==(const QWebEngineHttpRequestPrivate &other) const { return method == other.method && url == other.url @@ -128,10 +122,7 @@ QWebEngineHttpRequest::QWebEngineHttpRequest(const QUrl &url, /*! Creates a copy of \a other. */ -QWebEngineHttpRequest::QWebEngineHttpRequest(const QWebEngineHttpRequest &other) - : d(other.d) -{ -} +QWebEngineHttpRequest::QWebEngineHttpRequest(const QWebEngineHttpRequest &other) : d(other.d) {} /*! Disposes of the QWebEngineHttpRequest object. @@ -207,7 +198,6 @@ QWebEngineHttpRequest QWebEngineHttpRequest::postRequest(const QUrl &url, return result; } - /*! Returns the method this WebEngine request is using. @@ -291,8 +281,7 @@ bool QWebEngineHttpRequest::hasHeader(const QByteArray &headerName) const */ QByteArray QWebEngineHttpRequest::header(const QByteArray &headerName) const { - QWebEngineHttpRequestPrivate::Headers::ConstIterator it = - d->findHeader(headerName); + QWebEngineHttpRequestPrivate::Headers::ConstIterator it = d->findHeader(headerName); if (it != d->headers.constEnd()) return it->second; return QByteArray(); @@ -334,16 +323,15 @@ void QWebEngineHttpRequest::unsetHeader(const QByteArray &key) d->setHeader(key, QByteArray()); } -QWebEngineHttpRequestPrivate::Headers::ConstIterator -QWebEngineHttpRequestPrivate::findHeader(const QByteArray &key) const +QWebEngineHttpRequestPrivate::Headers::ConstIterator QWebEngineHttpRequestPrivate::findHeader(const QByteArray &key) const { Headers::ConstIterator it = headers.constBegin(); Headers::ConstIterator end = headers.constEnd(); - for ( ; it != end; ++it) + for (; it != end; ++it) if (qstricmp(it->first.constData(), key.constData()) == 0) return it; - return end; // not found + return end; // not found } QWebEngineHttpRequestPrivate::Headers QWebEngineHttpRequestPrivate::allHeaders() const @@ -355,9 +343,8 @@ QVector<QByteArray> QWebEngineHttpRequestPrivate::headersKeys() const { QVector<QByteArray> result; result.reserve(headers.size()); - Headers::ConstIterator it = headers.constBegin(), - end = headers.constEnd(); - for ( ; it != end; ++it) + Headers::ConstIterator it = headers.constBegin(), end = headers.constEnd(); + for (; it != end; ++it) result << it->first; return result; @@ -385,8 +372,7 @@ void QWebEngineHttpRequestPrivate::unsetHeader(const QByteArray &key) auto firstEqualsKey = [&key](const HeaderPair &header) { return qstricmp(header.first.constData(), key.constData()) == 0; }; - headers.erase(std::remove_if(headers.begin(), headers.end(), firstEqualsKey), - headers.end()); + headers.erase(std::remove_if(headers.begin(), headers.end(), firstEqualsKey), headers.end()); } /*! @@ -408,7 +394,7 @@ void QWebEngineHttpRequestPrivate::setHeaderInternal(const QByteArray &key, cons unsetHeader(key); if (value.isNull()) - return; // only wanted to erase key + return; // only wanted to erase key HeaderPair pair; pair.first = key; diff --git a/src/core/api/qwebenginehttprequest.h b/src/core/api/qwebenginehttprequest.h index c6b5a6b63..1c4d7837b 100644 --- a/src/core/api/qwebenginehttprequest.h +++ b/src/core/api/qwebenginehttprequest.h @@ -49,11 +49,9 @@ QT_BEGIN_NAMESPACE - class QWebEngineHttpRequestPrivate; -class QWEBENGINECORE_EXPORT QWebEngineHttpRequest -{ +class Q_WEBENGINECORE_EXPORT QWebEngineHttpRequest { public: enum Method { Get, @@ -61,22 +59,23 @@ public: }; explicit QWebEngineHttpRequest(const QUrl &url = QUrl(), - const QWebEngineHttpRequest::Method &method = QWebEngineHttpRequest::Get); + const QWebEngineHttpRequest::Method &method = QWebEngineHttpRequest::Get); QWebEngineHttpRequest(const QWebEngineHttpRequest &other); ~QWebEngineHttpRequest(); #ifdef Q_COMPILER_RVALUE_REFS - QWebEngineHttpRequest &operator=(QWebEngineHttpRequest &&other) Q_DECL_NOTHROW { swap(other); - return *this; } + QWebEngineHttpRequest &operator=(QWebEngineHttpRequest &&other) Q_DECL_NOTHROW + { + swap(other); + return *this; + } #endif QWebEngineHttpRequest &operator=(const QWebEngineHttpRequest &other); - static QWebEngineHttpRequest postRequest(const QUrl &url, - const QMap<QString, QString> &postData); + static QWebEngineHttpRequest postRequest(const QUrl &url, const QMap<QString, QString> &postData); void swap(QWebEngineHttpRequest &other) Q_DECL_NOTHROW { qSwap(d, other.d); } bool operator==(const QWebEngineHttpRequest &other) const; - inline bool operator!=(const QWebEngineHttpRequest &other) const - { return !operator==(other); } + inline bool operator!=(const QWebEngineHttpRequest &other) const { return !operator==(other); } Method method() const; void setMethod(QWebEngineHttpRequest::Method method); diff --git a/src/core/api/qwebenginemessagepumpscheduler_p.h b/src/core/api/qwebenginemessagepumpscheduler_p.h index 4c9e4d600..07b2ca203 100644 --- a/src/core/api/qwebenginemessagepumpscheduler_p.h +++ b/src/core/api/qwebenginemessagepumpscheduler_p.h @@ -59,8 +59,7 @@ QT_BEGIN_NAMESPACE -class QWEBENGINECORE_PRIVATE_EXPORT QWebEngineMessagePumpScheduler : public QObject -{ +class Q_WEBENGINECORE_PRIVATE_EXPORT QWebEngineMessagePumpScheduler : public QObject { Q_OBJECT public: QWebEngineMessagePumpScheduler(std::function<void()> callback); diff --git a/src/core/api/qwebenginenotification.cpp b/src/core/api/qwebenginenotification.cpp new file mode 100644 index 000000000..abc63fed2 --- /dev/null +++ b/src/core/api/qwebenginenotification.cpp @@ -0,0 +1,323 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwebenginenotification.h" + +#include "user_notification_controller.h" + +#include <QExplicitlySharedDataPointer> + +QT_BEGIN_NAMESPACE + +using QtWebEngineCore::UserNotificationController; + +/*! + \qmltype WebEngineNotification + \instantiates QWebEngineNotification + \inqmlmodule QtWebEngine + \since QtWebEngine 1.9 + \brief Encapsulates the data of an HTML5 web notification. + + This type contains the information and API for HTML5 desktop and push notifications. + + Web engine notifications are passed to the user in the + \l WebEngineProfile::presentNotification() signal. + + For more information about how to handle web notification, see the + \l{WebEngine Notifications Example}{Notification Example}. +*/ + +/*! + \class QWebEngineNotification + \brief The QWebEngineNotification class encapsulates the data of an HTML5 web notification. + \since 5.13 + + \inmodule QtWebEngineCore + + This class contains the information and API for HTML5 desktop and push notifications. + + Web engine notifications are passed to the user through the custom handler + provided with the \l QWebEngineProfile::setNotificationPresenter() call. + + For more information about how to handle web notification, see the + \l{WebEngine Notifications Example}{Notification Example}. +*/ + +class QWebEngineNotificationPrivate : public UserNotificationController::Client { +public: + QWebEngineNotificationPrivate(QWebEngineNotification *q, const QSharedPointer<UserNotificationController> &controller) + : controller(controller) + , q(q) + { + controller->setClient(this); + } + ~QWebEngineNotificationPrivate() override + { + if (controller->client() == this) + controller->setClient(0); + } + + // UserNotificationController::Client: + virtual void notificationClosed(const UserNotificationController *) override + { + Q_EMIT q->closed(); + } + + QSharedPointer<UserNotificationController> controller; + QWebEngineNotification *q; +}; + +/*! \internal +*/ +QWebEngineNotification::QWebEngineNotification(const QSharedPointer<UserNotificationController> &controller) + : d_ptr(new QWebEngineNotificationPrivate(this, controller)) +{} + +/*! \internal +*/ +QWebEngineNotification::~QWebEngineNotification() {} + +/*! + Returns \c true if the two notifications belong to the same message chain. + That is, if their tag() and origin() are the same. This means one is + a replacement or an update of the \a other. + + \sa tag(), origin() +*/ +bool QWebEngineNotification::matches(const QWebEngineNotification *other) const +{ + if (!other) + return false; + if (!d_ptr) + return !other->d_ptr; + if (!other->d_ptr) + return false; + return tag() == other->tag() && origin() == other->origin(); +} + +/*! + \qmlproperty bool WebEngineNotification::title + \brief The title of the notification. +*/ +/*! + \property QWebEngineNotification::title + \brief The title of the notification. + \sa message() +*/ +QString QWebEngineNotification::title() const +{ + Q_D(const QWebEngineNotification); + return d ? d->controller->title() : QString(); +} + +/*! + \qmlproperty string WebEngineNotification::message + \brief The body of the notification message. +*/ +/*! + \property QWebEngineNotification::message + \brief The body of the notification message. + \sa title() +*/ + +QString QWebEngineNotification::message() const +{ + Q_D(const QWebEngineNotification); + return d ? d->controller->body() : QString(); +} + +/*! + \qmlproperty string WebEngineNotification::tag + \brief The tag of the notification message. + + New notifications that have the same tag and origin URL as an existing + one should replace or update the old notification with the same tag. +*/ +/*! + \property QWebEngineNotification::tag + \brief The tag of the notification message. + + New notifications that have the same tag and origin URL as an existing + one should replace or update the old notification with the same tag. + + \sa matches() +*/ +QString QWebEngineNotification::tag() const +{ + Q_D(const QWebEngineNotification); + return d ? d->controller->tag() : QString(); +} + +/*! + \qmlproperty url WebEngineNotification::origin + \brief The URL of the page sending the notification. +*/ +/*! + \property QWebEngineNotification::origin + \brief The URL of the page sending the notification. +*/ + +QUrl QWebEngineNotification::origin() const +{ + Q_D(const QWebEngineNotification); + return d ? d->controller->origin() : QUrl(); +} + +/*! + Returns the icon to be shown with the notification. + + If no icon is set by the sender, a null QImage is returned. +*/ +QImage QWebEngineNotification::icon() const +{ + Q_D(const QWebEngineNotification); + return d ? d->controller->icon() : QImage(); +} + +/*! + \qmlproperty string WebEngineNotification::language + \brief The primary language for the notification's title and body. + + Its value is a valid BCP 47 language tag, or the empty string. +*/ +/*! + \property QWebEngineNotification::language + \brief The primary language for the notification's title and body. + + Its value is a valid BCP 47 language tag, or the empty string. + + \sa title(), message() +*/ +QString QWebEngineNotification::language() const +{ + Q_D(const QWebEngineNotification); + return d ? d->controller->language() : QString(); +} + +/*! + \qmlproperty enumeration WebEngineNotification::direction + \brief The text direction for the notification's title and body. + + \value Qt.LeftToRight Items are laid out from left to right. + \value Qt.RightToLeft Items are laid out from right to left. + \value Qt.LayoutDirectionAuto The direction to lay out items is determined automatically. +*/ +/*! + \property QWebEngineNotification::direction + \brief The text direction for the notification's title and body. + \sa title(), message() +*/ +Qt::LayoutDirection QWebEngineNotification::direction() const +{ + Q_D(const QWebEngineNotification); + return d ? d->controller->direction() : Qt::LayoutDirectionAuto; +} + +/*! + \qmlmethod void WebEngineNotification::show() + Creates and dispatches a JavaScript \e {show event} on notification. + + Should be called by the notification platform when the notification has been shown to user. +*/ +/*! + Creates and dispatches a JavaScript \e {show event} on notification. + + Should be called by the notification platform when the notification has been shown to user. +*/ +void QWebEngineNotification::show() const +{ + Q_D(const QWebEngineNotification); + if (d) + d->controller->notificationDisplayed(); +} + +/*! + \qmlmethod void WebEngineNotification::click() + Creates and dispatches a JavaScript \e {click event} on notification. + + Should be called by the notification platform when the notification is activated by the user. +*/ +/*! + Creates and dispatches a JavaScript \e {click event} on notification. + + Should be called by the notification platform when the notification is activated by the user. +*/ +void QWebEngineNotification::click() const +{ + Q_D(const QWebEngineNotification); + if (d) + d->controller->notificationClicked(); +} + +/*! + \qmlmethod void WebEngineNotification::close() + Creates and dispatches a JavaScript \e {close event} on notification. + + Should be called by the notification platform when the notification is closed, + either by the underlying platform or by the user. +*/ +/*! + Creates and dispatches a JavaScript \e {close event} on notification. + + Should be called by the notification platform when the notification is closed, + either by the underlying platform or by the user. +*/ +void QWebEngineNotification::close() const +{ + Q_D(const QWebEngineNotification); + if (d) + d->controller->notificationClosed(); +} + +/*! + \qmlsignal WebEngineNotification::closed() + + This signal is emitted when the web page calls close steps for the notification, + and it no longer needs to be shown. +*/ +/*! + \fn void QWebEngineNotification::closed() + + This signal is emitted when the web page calls close steps for the notification, + and it no longer needs to be shown. +*/ + +QT_END_NAMESPACE + +#include "moc_qwebenginenotification.cpp" diff --git a/src/core/api/qwebenginenotification.h b/src/core/api/qwebenginenotification.h new file mode 100644 index 000000000..08fd629be --- /dev/null +++ b/src/core/api/qwebenginenotification.h @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWEBENGINENOTIFICATION_H +#define QWEBENGINENOTIFICATION_H + +#include <QtWebEngineCore/qtwebenginecoreglobal.h> + +#include <QtCore/QObject> +#include <QtCore/QScopedPointer> +#include <QtCore/QSharedPointer> +#include <QtCore/QUrl> + +namespace QtWebEngineCore { +class UserNotificationController; +} + +QT_BEGIN_NAMESPACE + +class QWebEngineNotificationPrivate; + +class Q_WEBENGINECORE_EXPORT QWebEngineNotification : public QObject { + Q_OBJECT + Q_PROPERTY(QUrl origin READ origin CONSTANT FINAL) + Q_PROPERTY(QString title READ title CONSTANT FINAL) + Q_PROPERTY(QString message READ message CONSTANT FINAL) + Q_PROPERTY(QString tag READ tag CONSTANT FINAL) + Q_PROPERTY(QString language READ language CONSTANT FINAL) + Q_PROPERTY(Qt::LayoutDirection direction READ direction CONSTANT FINAL) + +public: + virtual ~QWebEngineNotification() override; + + bool matches(const QWebEngineNotification *other) const; + + QUrl origin() const; + QImage icon() const; + QString title() const; + QString message() const; + QString tag() const; + QString language() const; + Qt::LayoutDirection direction() const; + +public Q_SLOTS: + void show() const; + void click() const; + void close() const; + +Q_SIGNALS: + void closed(); + +private: + Q_DISABLE_COPY(QWebEngineNotification) + Q_DECLARE_PRIVATE(QWebEngineNotification) + QWebEngineNotification(const QSharedPointer<QtWebEngineCore::UserNotificationController> &controller); + QScopedPointer<QWebEngineNotificationPrivate> d_ptr; + friend class QQuickWebEngineProfilePrivate; + friend class QWebEngineProfilePrivate; +}; + +QT_END_NAMESPACE + +#endif // QWEBENGINENOTIFICATION_H diff --git a/src/core/api/qwebenginequotarequest.cpp b/src/core/api/qwebenginequotarequest.cpp index 49c9f041f..7686d0806 100644 --- a/src/core/api/qwebenginequotarequest.cpp +++ b/src/core/api/qwebenginequotarequest.cpp @@ -64,8 +64,7 @@ QT_BEGIN_NAMESPACE /*! \internal */ QWebEngineQuotaRequest::QWebEngineQuotaRequest(QSharedPointer<QtWebEngineCore::QuotaRequestController> controller) : d_ptr(controller) -{ -} +{} /*! Rejects a request for larger persistent storage. diff --git a/src/core/api/qwebenginequotarequest.h b/src/core/api/qwebenginequotarequest.h index a759f5bb6..da72116c8 100644 --- a/src/core/api/qwebenginequotarequest.h +++ b/src/core/api/qwebenginequotarequest.h @@ -47,11 +47,11 @@ namespace QtWebEngineCore { class QuotaPermissionContextQt; class QuotaRequestController; -} +} // namespace QtWebEngineCore QT_BEGIN_NAMESPACE -class QWEBENGINECORE_EXPORT QWebEngineQuotaRequest { +class Q_WEBENGINECORE_EXPORT QWebEngineQuotaRequest { Q_GADGET Q_PROPERTY(QUrl origin READ origin CONSTANT FINAL) Q_PROPERTY(qint64 requestedSize READ requestedSize CONSTANT FINAL) @@ -63,6 +63,7 @@ public: qint64 requestedSize() const; bool operator==(const QWebEngineQuotaRequest &that) const { return d_ptr == that.d_ptr; } bool operator!=(const QWebEngineQuotaRequest &that) const { return d_ptr != that.d_ptr; } + private: QWebEngineQuotaRequest(QSharedPointer<QtWebEngineCore::QuotaRequestController>); friend QtWebEngineCore::QuotaPermissionContextQt; diff --git a/src/core/api/qwebengineregisterprotocolhandlerrequest.cpp b/src/core/api/qwebengineregisterprotocolhandlerrequest.cpp index 1921f78f4..a3960327d 100644 --- a/src/core/api/qwebengineregisterprotocolhandlerrequest.cpp +++ b/src/core/api/qwebengineregisterprotocolhandlerrequest.cpp @@ -59,7 +59,7 @@ QT_BEGIN_NAMESPACE /*! \internal */ QWebEngineRegisterProtocolHandlerRequest::QWebEngineRegisterProtocolHandlerRequest( - QSharedPointer<QtWebEngineCore::RegisterProtocolHandlerRequestController> d_ptr) + QSharedPointer<QtWebEngineCore::RegisterProtocolHandlerRequestController> d_ptr) : d_ptr(std::move(d_ptr)) {} diff --git a/src/core/api/qwebengineregisterprotocolhandlerrequest.h b/src/core/api/qwebengineregisterprotocolhandlerrequest.h index 12b1d6edf..67caf1590 100644 --- a/src/core/api/qwebengineregisterprotocolhandlerrequest.h +++ b/src/core/api/qwebengineregisterprotocolhandlerrequest.h @@ -47,11 +47,11 @@ namespace QtWebEngineCore { class RegisterProtocolHandlerRequestController; class WebContentsDelegateQt; -} +} // namespace QtWebEngineCore QT_BEGIN_NAMESPACE -class QWEBENGINECORE_EXPORT QWebEngineRegisterProtocolHandlerRequest { +class Q_WEBENGINECORE_EXPORT QWebEngineRegisterProtocolHandlerRequest { Q_GADGET Q_PROPERTY(QUrl origin READ origin CONSTANT FINAL) Q_PROPERTY(QString scheme READ scheme CONSTANT FINAL) @@ -63,9 +63,9 @@ public: QString scheme() const; bool operator==(const QWebEngineRegisterProtocolHandlerRequest &that) const { return d_ptr == that.d_ptr; } bool operator!=(const QWebEngineRegisterProtocolHandlerRequest &that) const { return d_ptr != that.d_ptr; } + private: - QWebEngineRegisterProtocolHandlerRequest( - QSharedPointer<QtWebEngineCore::RegisterProtocolHandlerRequestController>); + QWebEngineRegisterProtocolHandlerRequest(QSharedPointer<QtWebEngineCore::RegisterProtocolHandlerRequestController>); friend QtWebEngineCore::WebContentsDelegateQt; QSharedPointer<QtWebEngineCore::RegisterProtocolHandlerRequestController> d_ptr; }; diff --git a/src/core/api/qwebengineurlrequestinfo.cpp b/src/core/api/qwebengineurlrequestinfo.cpp index 2b8a69c9a..3cbb4da17 100644 --- a/src/core/api/qwebengineurlrequestinfo.cpp +++ b/src/core/api/qwebengineurlrequestinfo.cpp @@ -68,8 +68,10 @@ ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypeLast, content::RESOURCE ASSERT_ENUMS_MATCH(QtWebEngineCore::WebContentsAdapterClient::LinkNavigation, QWebEngineUrlRequestInfo::NavigationTypeLink) ASSERT_ENUMS_MATCH(QtWebEngineCore::WebContentsAdapterClient::TypedNavigation, QWebEngineUrlRequestInfo::NavigationTypeTyped) -ASSERT_ENUMS_MATCH(QtWebEngineCore::WebContentsAdapterClient::FormSubmittedNavigation, QWebEngineUrlRequestInfo::NavigationTypeFormSubmitted) -ASSERT_ENUMS_MATCH(QtWebEngineCore::WebContentsAdapterClient::BackForwardNavigation, QWebEngineUrlRequestInfo::NavigationTypeBackForward) +ASSERT_ENUMS_MATCH(QtWebEngineCore::WebContentsAdapterClient::FormSubmittedNavigation, + QWebEngineUrlRequestInfo::NavigationTypeFormSubmitted) +ASSERT_ENUMS_MATCH(QtWebEngineCore::WebContentsAdapterClient::BackForwardNavigation, + QWebEngineUrlRequestInfo::NavigationTypeBackForward) ASSERT_ENUMS_MATCH(QtWebEngineCore::WebContentsAdapterClient::ReloadNavigation, QWebEngineUrlRequestInfo::NavigationTypeReload) ASSERT_ENUMS_MATCH(QtWebEngineCore::WebContentsAdapterClient::OtherNavigation, QWebEngineUrlRequestInfo::NavigationTypeOther) @@ -96,8 +98,8 @@ ASSERT_ENUMS_MATCH(QtWebEngineCore::WebContentsAdapterClient::OtherNavigation, Q interceptor on the profile enables intercepting, blocking, and modifying URL requests before they reach the networking stack of Chromium. - You can install the interceptor on a profile via QWebEngineProfile::setRequestInterceptor() - or QQuickWebEngineProfile::setRequestInterceptor(). + You can install the interceptor on a profile via QWebEngineProfile::setUrlRequestInterceptor() + or QQuickWebEngineProfile::setUrlRequestInterceptor(). When using the \l{Qt WebEngine Widgets Module}, \l{QWebEnginePage::acceptNavigationRequest()} offers further options to accept or block requests. @@ -115,8 +117,7 @@ ASSERT_ENUMS_MATCH(QtWebEngineCore::WebContentsAdapterClient::OtherNavigation, Q \fn void QWebEngineUrlRequestInterceptor::interceptRequest(QWebEngineUrlRequestInfo &info) Reimplementing this virtual function makes it possible to intercept URL - requests. This function is executed on the IO thread, and therefore running - long tasks here will block networking. + requests. This method will be stalling the URL request until handled. \a info contains the information about the URL request and will track internally whether its members have been altered. @@ -125,8 +126,9 @@ ASSERT_ENUMS_MATCH(QtWebEngineCore::WebContentsAdapterClient::OtherNavigation, Q execution of this function is finished. */ - -QWebEngineUrlRequestInfoPrivate::QWebEngineUrlRequestInfoPrivate(QWebEngineUrlRequestInfo::ResourceType resource, QWebEngineUrlRequestInfo::NavigationType navigation, const QUrl &u, const QUrl &fpu, const QByteArray &m) +QWebEngineUrlRequestInfoPrivate::QWebEngineUrlRequestInfoPrivate(QWebEngineUrlRequestInfo::ResourceType resource, + QWebEngineUrlRequestInfo::NavigationType navigation, + const QUrl &u, const QUrl &fpu, const QByteArray &m) : resourceType(resource) , navigationType(navigation) , shouldBlockRequest(false) @@ -134,24 +136,24 @@ QWebEngineUrlRequestInfoPrivate::QWebEngineUrlRequestInfoPrivate(QWebEngineUrlRe , firstPartyUrl(fpu) , method(m) , changed(false) -{ -} +{} /*! \internal */ +QWebEngineUrlRequestInfo::QWebEngineUrlRequestInfo(QWebEngineUrlRequestInfo &&p) : d_ptr(p.d_ptr.take()) {} -QWebEngineUrlRequestInfo::~QWebEngineUrlRequestInfo() -{ +/*! + \internal +*/ -} +QWebEngineUrlRequestInfo::~QWebEngineUrlRequestInfo() {} /*! \internal */ -QWebEngineUrlRequestInfo::QWebEngineUrlRequestInfo(QWebEngineUrlRequestInfoPrivate *p) - : d_ptr(p) +QWebEngineUrlRequestInfo::QWebEngineUrlRequestInfo(QWebEngineUrlRequestInfoPrivate *p) : d_ptr(p) { d_ptr->q_ptr = this; } @@ -241,7 +243,6 @@ QUrl QWebEngineUrlRequestInfo::firstPartyUrl() const return d_ptr->firstPartyUrl; } - /*! Returns the HTTP method of the request (for example, GET or POST). */ @@ -260,6 +261,14 @@ bool QWebEngineUrlRequestInfo::changed() const } /*! + \internal +*/ +void QWebEngineUrlRequestInfo::resetChanged() +{ + d_ptr->changed = false; +} + +/*! Redirects this request to \a url. It is only possible to redirect requests that do not have payload data, such as GET requests. */ diff --git a/src/core/api/qwebengineurlrequestinfo.h b/src/core/api/qwebengineurlrequestinfo.h index 68c46dcf4..cf5a4801d 100644 --- a/src/core/api/qwebengineurlrequestinfo.h +++ b/src/core/api/qwebengineurlrequestinfo.h @@ -47,13 +47,14 @@ namespace QtWebEngineCore { class NetworkDelegateQt; -} +class URLRequestNotification; +} // namespace QtWebEngineCore QT_BEGIN_NAMESPACE class QWebEngineUrlRequestInfoPrivate; -class QWEBENGINECORE_EXPORT QWebEngineUrlRequestInfo { +class Q_WEBENGINECORE_EXPORT QWebEngineUrlRequestInfo { public: enum ResourceType { ResourceTypeMainFrame = 0, // top level page @@ -104,10 +105,14 @@ public: private: friend class QtWebEngineCore::NetworkDelegateQt; + friend class QtWebEngineCore::URLRequestNotification; Q_DISABLE_COPY(QWebEngineUrlRequestInfo) Q_DECLARE_PRIVATE(QWebEngineUrlRequestInfo) + void resetChanged(); + QWebEngineUrlRequestInfo(QWebEngineUrlRequestInfoPrivate *p); + QWebEngineUrlRequestInfo(QWebEngineUrlRequestInfo &&p); ~QWebEngineUrlRequestInfo(); QScopedPointer<QWebEngineUrlRequestInfoPrivate> d_ptr; }; diff --git a/src/core/api/qwebengineurlrequestinfo_p.h b/src/core/api/qwebengineurlrequestinfo_p.h index 9afd04398..9d795b2b5 100644 --- a/src/core/api/qwebengineurlrequestinfo_p.h +++ b/src/core/api/qwebengineurlrequestinfo_p.h @@ -65,15 +65,12 @@ class URLRequest; QT_BEGIN_NAMESPACE -class QWebEngineUrlRequestInfoPrivate -{ +class QWebEngineUrlRequestInfoPrivate { Q_DECLARE_PUBLIC(QWebEngineUrlRequestInfo) public: - QWebEngineUrlRequestInfoPrivate(QWebEngineUrlRequestInfo::ResourceType resource - , QWebEngineUrlRequestInfo::NavigationType navigation - , const QUrl &u - , const QUrl &fpu - , const QByteArray &m); + QWebEngineUrlRequestInfoPrivate(QWebEngineUrlRequestInfo::ResourceType resource, + QWebEngineUrlRequestInfo::NavigationType navigation, const QUrl &u, const QUrl &fpu, + const QByteArray &m); QWebEngineUrlRequestInfo::ResourceType resourceType; QWebEngineUrlRequestInfo::NavigationType navigationType; diff --git a/src/core/api/qwebengineurlrequestinterceptor.h b/src/core/api/qwebengineurlrequestinterceptor.h index dc2a15ee3..4d3020306 100644 --- a/src/core/api/qwebengineurlrequestinterceptor.h +++ b/src/core/api/qwebengineurlrequestinterceptor.h @@ -50,15 +50,11 @@ QT_BEGIN_NAMESPACE -class QWEBENGINECORE_EXPORT QWebEngineUrlRequestInterceptor : public QObject -{ +class Q_WEBENGINECORE_EXPORT QWebEngineUrlRequestInterceptor : public QObject { Q_OBJECT Q_DISABLE_COPY(QWebEngineUrlRequestInterceptor) public: - explicit QWebEngineUrlRequestInterceptor(QObject *p = Q_NULLPTR) - : QObject (p) - { - } + explicit QWebEngineUrlRequestInterceptor(QObject *p = nullptr) : QObject(p) {} virtual void interceptRequest(QWebEngineUrlRequestInfo &info) = 0; }; diff --git a/src/core/api/qwebengineurlrequestjob.cpp b/src/core/api/qwebengineurlrequestjob.cpp index c3541598b..3bb9d1732 100644 --- a/src/core/api/qwebengineurlrequestjob.cpp +++ b/src/core/api/qwebengineurlrequestjob.cpp @@ -84,11 +84,10 @@ QT_BEGIN_NAMESPACE /*! \internal */ -QWebEngineUrlRequestJob::QWebEngineUrlRequestJob(URLRequestCustomJobDelegate * p) +QWebEngineUrlRequestJob::QWebEngineUrlRequestJob(URLRequestCustomJobDelegate *p) : QObject(p) // owned by the jobdelegate and deleted when the job is done , d_ptr(p) -{ -} +{} /*! \internal @@ -140,6 +139,15 @@ QUrl QWebEngineUrlRequestJob::initiator() const } /*! + \since 5.13 + Returns any HTTP headers added to the request. +*/ +QMap<QByteArray, QByteArray> QWebEngineUrlRequestJob::requestHeaders() const +{ + return d_ptr->requestHeaders(); +} + +/*! Replies to the request with \a device and the MIME type \a contentType. The user has to be aware that \a device will be used on another thread diff --git a/src/core/api/qwebengineurlrequestjob.h b/src/core/api/qwebengineurlrequestjob.h index 7ce8be7ec..6d4a9e734 100644 --- a/src/core/api/qwebengineurlrequestjob.h +++ b/src/core/api/qwebengineurlrequestjob.h @@ -49,13 +49,13 @@ namespace QtWebEngineCore { class URLRequestCustomJobDelegate; class URLRequestCustomJobProxy; -} // namespace +} // namespace QtWebEngineCore QT_BEGIN_NAMESPACE class QIODevice; -class QWEBENGINECORE_EXPORT QWebEngineUrlRequestJob : public QObject { +class Q_WEBENGINECORE_EXPORT QWebEngineUrlRequestJob : public QObject { Q_OBJECT public: ~QWebEngineUrlRequestJob(); @@ -73,6 +73,7 @@ public: QUrl requestUrl() const; QByteArray requestMethod() const; QUrl initiator() const; + QMap<QByteArray, QByteArray> requestHeaders() const; void reply(const QByteArray &contentType, QIODevice *device); void fail(Error error); @@ -82,7 +83,7 @@ private: QWebEngineUrlRequestJob(QtWebEngineCore::URLRequestCustomJobDelegate *); friend class QtWebEngineCore::URLRequestCustomJobProxy; - QtWebEngineCore::URLRequestCustomJobDelegate* d_ptr; + QtWebEngineCore::URLRequestCustomJobDelegate *d_ptr; }; QT_END_NAMESPACE diff --git a/src/core/api/qwebengineurlscheme.cpp b/src/core/api/qwebengineurlscheme.cpp index 9cc5b5056..f4efad717 100644 --- a/src/core/api/qwebengineurlscheme.cpp +++ b/src/core/api/qwebengineurlscheme.cpp @@ -48,8 +48,7 @@ QT_BEGIN_NAMESPACE ASSERT_ENUMS_MATCH(QWebEngineUrlScheme::Syntax::Path, url::SCHEME_WITHOUT_AUTHORITY) ASSERT_ENUMS_MATCH(QWebEngineUrlScheme::Syntax::Host, url::SCHEME_WITH_HOST) ASSERT_ENUMS_MATCH(QWebEngineUrlScheme::Syntax::HostAndPort, url::SCHEME_WITH_HOST_AND_PORT) -ASSERT_ENUMS_MATCH(QWebEngineUrlScheme::Syntax::HostPortAndUserInformation, - url::SCHEME_WITH_HOST_PORT_AND_USER_INFORMATION) +ASSERT_ENUMS_MATCH(QWebEngineUrlScheme::Syntax::HostPortAndUserInformation, url::SCHEME_WITH_HOST_PORT_AND_USER_INFORMATION) ASSERT_ENUMS_MATCH(QWebEngineUrlScheme::PortUnspecified, url::PORT_UNSPECIFIED) @@ -193,10 +192,7 @@ public: Content-Security-Policy checks. */ -QWebEngineUrlScheme::QWebEngineUrlScheme(QWebEngineUrlSchemePrivate *d) - : d(d) -{ -} +QWebEngineUrlScheme::QWebEngineUrlScheme(QWebEngineUrlSchemePrivate *d) : d(d) {} /*! Constructs a web engine URL scheme with default values. @@ -399,7 +395,7 @@ void QWebEngineUrlScheme::registerScheme(const QWebEngineUrlScheme &scheme) */ QWebEngineUrlScheme QWebEngineUrlScheme::schemeByName(const QByteArray &name) { - base::StringPiece namePiece{name.data(), static_cast<size_t>(name.size())}; + base::StringPiece 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/qwebengineurlscheme.h b/src/core/api/qwebengineurlscheme.h index da3010335..095b47320 100644 --- a/src/core/api/qwebengineurlscheme.h +++ b/src/core/api/qwebengineurlscheme.h @@ -46,13 +46,15 @@ #include <QtCore/qobjectdefs.h> #include <QtCore/qshareddata.h> -namespace QtWebEngineCore { class WebEngineContext; } +namespace QtWebEngineCore { +class WebEngineContext; +} QT_BEGIN_NAMESPACE class QWebEngineUrlSchemePrivate; -class QWEBENGINECORE_EXPORT QWebEngineUrlScheme { +class Q_WEBENGINECORE_EXPORT QWebEngineUrlScheme { Q_GADGET public: enum class Syntax { diff --git a/src/core/api/qwebengineurlschemehandler.cpp b/src/core/api/qwebengineurlschemehandler.cpp index b5912703d..aecee5044 100644 --- a/src/core/api/qwebengineurlschemehandler.cpp +++ b/src/core/api/qwebengineurlschemehandler.cpp @@ -111,7 +111,6 @@ QWebEngineUrlSchemeHandler::QWebEngineUrlSchemeHandler(QObject *parent) */ QWebEngineUrlSchemeHandler::~QWebEngineUrlSchemeHandler() { - Q_EMIT _q_destroyedUrlSchemeHandler(this); } /*! diff --git a/src/core/api/qwebengineurlschemehandler.h b/src/core/api/qwebengineurlschemehandler.h index 23fee4b95..09c5b08cb 100644 --- a/src/core/api/qwebengineurlschemehandler.h +++ b/src/core/api/qwebengineurlschemehandler.h @@ -52,18 +52,13 @@ QT_BEGIN_NAMESPACE class QWebEngineUrlRequestJob; -class QWEBENGINECORE_EXPORT QWebEngineUrlSchemeHandler : public QObject { +class Q_WEBENGINECORE_EXPORT QWebEngineUrlSchemeHandler : public QObject { Q_OBJECT public: QWebEngineUrlSchemeHandler(QObject *parent = Q_NULLPTR); ~QWebEngineUrlSchemeHandler(); - virtual void requestStarted(QWebEngineUrlRequestJob*) = 0; - -#ifndef Q_QDOC -Q_SIGNALS: - void _q_destroyedUrlSchemeHandler(QWebEngineUrlSchemeHandler*); -#endif + virtual void requestStarted(QWebEngineUrlRequestJob *) = 0; private: Q_DISABLE_COPY(QWebEngineUrlSchemeHandler) diff --git a/src/core/authentication_dialog_controller.cpp b/src/core/authentication_dialog_controller.cpp index bd23d1768..1133b0bc1 100644 --- a/src/core/authentication_dialog_controller.cpp +++ b/src/core/authentication_dialog_controller.cpp @@ -40,7 +40,9 @@ #include "authentication_dialog_controller.h" #include "authentication_dialog_controller_p.h" +#include "base/task/post_task.h" #include "content/public/browser/browser_thread.h" +#include "content/public/browser/browser_task_traits.h" namespace QtWebEngineCore { @@ -51,9 +53,10 @@ AuthenticationDialogControllerPrivate::AuthenticationDialogControllerPrivate(Log void AuthenticationDialogControllerPrivate::dialogFinished(bool accepted, const QString &user, const QString &password) { - content::BrowserThread::PostTask( - content::BrowserThread::IO, FROM_HERE, - base::Bind(&LoginDelegateQt::sendAuthToRequester, loginDelegate, accepted, user, password)); + base::PostTaskWithTraits( + FROM_HERE, {content::BrowserThread::IO}, + base::BindOnce(&LoginDelegateQt::sendAuthToRequester, + loginDelegate, accepted, user, password)); } AuthenticationDialogController::AuthenticationDialogController(AuthenticationDialogControllerPrivate *dd) diff --git a/src/core/authentication_dialog_controller.h b/src/core/authentication_dialog_controller.h index aec91aac5..631a95c34 100644 --- a/src/core/authentication_dialog_controller.h +++ b/src/core/authentication_dialog_controller.h @@ -59,7 +59,7 @@ namespace QtWebEngineCore { class AuthenticationDialogControllerPrivate; -class QWEBENGINECORE_PRIVATE_EXPORT AuthenticationDialogController : public QObject { +class Q_WEBENGINECORE_PRIVATE_EXPORT AuthenticationDialogController : public QObject { Q_OBJECT public: ~AuthenticationDialogController(); diff --git a/src/core/browser_accessibility_qt.cpp b/src/core/browser_accessibility_qt.cpp index 29fbbc542..75527ea95 100644 --- a/src/core/browser_accessibility_qt.cpp +++ b/src/core/browser_accessibility_qt.cpp @@ -61,6 +61,11 @@ const BrowserAccessibilityQt *ToBrowserAccessibilityQt(const BrowserAccessibilit return static_cast<const BrowserAccessibilityQt *>(obj); } +QAccessibleInterface *toQAccessibleInterface(BrowserAccessibility *obj) +{ + return static_cast<BrowserAccessibilityQt *>(obj); +} + BrowserAccessibilityQt::BrowserAccessibilityQt() { QAccessible::registerAccessibleInterface(this); @@ -357,6 +362,8 @@ QAccessible::Role BrowserAccessibilityQt::role() const return QAccessible::EditableText; case ax::mojom::Role::kInputTime: return QAccessible::SpinBox; + case ax::mojom::Role::kKeyboard: + return QAccessible::NoRole; // FIXME case ax::mojom::Role::kLabelText: return QAccessible::StaticText; case ax::mojom::Role::kLayoutTable: diff --git a/src/core/browser_accessibility_qt.h b/src/core/browser_accessibility_qt.h index 345ee9862..decfc1e9d 100644 --- a/src/core/browser_accessibility_qt.h +++ b/src/core/browser_accessibility_qt.h @@ -146,6 +146,7 @@ public: }; const BrowserAccessibilityQt *ToBrowserAccessibilityQt(const BrowserAccessibility *obj); +QAccessibleInterface *toQAccessibleInterface(BrowserAccessibility *acc); } // namespace content diff --git a/src/core/browser_main_parts_qt.cpp b/src/core/browser_main_parts_qt.cpp index 3d85c04c4..dacaf177f 100644 --- a/src/core/browser_main_parts_qt.cpp +++ b/src/core/browser_main_parts_qt.cpp @@ -42,11 +42,22 @@ #include "api/qwebenginemessagepumpscheduler_p.h" #include "base/message_loop/message_loop.h" +#include "base/message_loop/message_loop_impl.h" +#include "base/message_loop/message_loop_current.h" #include "base/process/process.h" #include "base/threading/thread_restrictions.h" #include "content/public/browser/browser_main_parts.h" #include "content/public/browser/browser_thread.h" +#include "content/public/browser/child_process_security_policy.h" #include "content/public/common/service_manager_connection.h" +#include "extensions/buildflags/buildflags.h" +#if BUILDFLAG(ENABLE_EXTENSIONS) +#include "extensions/common/constants.h" +#include "extensions/common/extensions_client.h" +#include "extensions/extensions_browser_client_qt.h" +#include "extensions/extension_system_factory_qt.h" +#include "common/extensions/extensions_client_qt.h" +#endif //BUILDFLAG(ENABLE_EXTENSIONS) #include "services/resource_coordinator/public/cpp/process_resource_coordinator.h" #include "services/resource_coordinator/public/cpp/resource_coordinator_features.h" #include "services/service_manager/public/cpp/connector.h" @@ -56,7 +67,12 @@ #include "service/service_qt.h" #include "web_engine_context.h" -#include <QEventLoop> +#include <QtGui/qtgui-config.h> + +#if QT_CONFIG(opengl) +#include "ui/gl/gl_context.h" +#include <QOpenGLContext> +#endif #if defined(OS_MACOSX) #include "ui/base/idle/idle.h" @@ -89,6 +105,8 @@ int GetTimeIntervalMilliseconds(const base::TimeTicks &from) return delay < 0 ? 0 : delay; } +} // anonymous namespace + class MessagePumpForUIQt : public base::MessagePump { public: @@ -96,43 +114,86 @@ public: : m_scheduler([this]() { handleScheduledWork(); }) {} + void setDelegate(Delegate *delegate) + { + m_delegate = delegate; + } + void Run(Delegate *delegate) override { - if (!m_delegate) - m_delegate = delegate; - else - Q_ASSERT(delegate == m_delegate); // This is used only when MessagePumpForUIQt is used outside of the GUI thread. - QEventLoop loop; - m_explicitLoop = &loop; - loop.exec(); - m_explicitLoop = nullptr; + NOTIMPLEMENTED(); } void Quit() override { - Q_ASSERT(m_explicitLoop); - m_explicitLoop->quit(); + // This is used only when MessagePumpForUIQt is used outside of the GUI thread. + NOTIMPLEMENTED(); } void ScheduleWork() override { // NOTE: This method may called from any thread at any time. - if (!m_delegate) - m_delegate = base::MessageLoopForUI::current(); m_scheduler.scheduleWork(); } void ScheduleDelayedWork(const base::TimeTicks &delayed_work_time) override { - if (!m_delegate) - m_delegate = base::MessageLoopForUI::current(); m_scheduler.scheduleDelayedWork(GetTimeIntervalMilliseconds(delayed_work_time)); } private: + // Both Qt and Chromium keep track of the current GL context by using + // thread-local variables, and naturally they are completely unaware of each + // other. As a result, when a QOpenGLContext is made current, the previous + // gl::GLContext is not released, and vice-versa. This is fine as long as + // each thread uses exclusively either Qt or Chromium GL bindings, which is + // usually the case. + // + // The only exception is when the GL driver is considered thread-unsafe + // (QOpenGLContext::supportsThreadedOpenGL() is false), in which case we + // have to run all GL operations, including Chromium's GPU service, on the + // UI thread. Now the bindings are being mixed and both Qt and Chromium get + // quite confused regarding the current state of the surface. + // + // To get this to work we have to release the current QOpenGLContext before + // executing any tasks from Chromium's GPU service and the gl::GLContext + // afterwards. Since GPU service just posts tasks to the UI thread task + // runner, we'll have to instrument the entire UI thread message pump. + class ScopedGLContextChecker + { +#if QT_CONFIG(opengl) + public: + ScopedGLContextChecker() + { + if (!m_enabled) + return; + + if (QOpenGLContext *context = QOpenGLContext::currentContext()) + context->doneCurrent(); + } + + ~ScopedGLContextChecker() + { + if (!m_enabled) + return; + + if (gl::GLContext *context = gl::GLContext::GetCurrent()) + context->ReleaseCurrent(nullptr); + } + + private: + bool m_enabled = !QOpenGLContext::supportsThreadedOpenGL(); +#endif // QT_CONFIG(opengl) + }; + + void handleScheduledWork() { + Q_ASSERT(m_delegate); + + ScopedGLContextChecker glContextChecker; + bool more_work_is_plausible = m_delegate->DoWork(); base::TimeTicks delayed_work_time; @@ -149,16 +210,26 @@ private: } Delegate *m_delegate = nullptr; - QEventLoop *m_explicitLoop = nullptr; QWebEngineMessagePumpScheduler m_scheduler; }; -} // anonymous namespace +// Needed to access protected constructor from MessageLoop. +class MessageLoopForUIQt : public base::MessageLoop { +public: + MessageLoopForUIQt() : MessageLoop(TYPE_UI, base::BindOnce(&messagePumpFactory)) + { + BindToCurrentThread(); -std::unique_ptr<base::MessagePump> messagePumpFactory() -{ - return base::WrapUnique(new MessagePumpForUIQt); -} + auto pump = static_cast<MessagePumpForUIQt *>(pump_); + auto backend = static_cast<base::MessageLoopImpl *>(backend_.get()); + pump->setDelegate(backend); + } +private: + static std::unique_ptr<base::MessagePump> messagePumpFactory() + { + return base::WrapUnique(new MessagePumpForUIQt); + } +}; BrowserMainPartsQt::BrowserMainPartsQt() : content::BrowserMainParts() { } @@ -168,12 +239,25 @@ BrowserMainPartsQt::~BrowserMainPartsQt() = default; int BrowserMainPartsQt::PreEarlyInitialization() { - base::MessageLoop::InitMessagePumpForUIFactory(messagePumpFactory); +#if BUILDFLAG(ENABLE_EXTENSIONS) + content::ChildProcessSecurityPolicy::GetInstance()->RegisterWebSafeScheme(extensions::kExtensionScheme); +#endif //ENABLE_EXTENSIONS return 0; } void BrowserMainPartsQt::PreMainMessageLoopStart() { + // Overrides message loop creation in BrowserMainLoop::MainMessageLoopStart(). + m_mainMessageLoop.reset(new MessageLoopForUIQt); +} + +void BrowserMainPartsQt::PreMainMessageLoopRun() +{ +#if BUILDFLAG(ENABLE_EXTENSIONS) + extensions::ExtensionsClient::Set(new extensions::ExtensionsClientQt()); + extensions::ExtensionsBrowserClient::Set(new extensions::ExtensionsBrowserClientQt()); + extensions::ExtensionSystemFactoryQt::GetInstance(); +#endif //ENABLE_EXTENSIONS } void BrowserMainPartsQt::PostMainMessageLoopRun() @@ -203,12 +287,9 @@ int BrowserMainPartsQt::PreCreateThreads() void BrowserMainPartsQt::ServiceManagerConnectionStarted(content::ServiceManagerConnection *connection) { ServiceQt::GetInstance()->InitConnector(); - connection->GetConnector()->StartService(service_manager::Identity("qtwebengine")); - if (resource_coordinator::IsResourceCoordinatorEnabled()) { - m_processResourceCoordinator = std::make_unique<resource_coordinator::ProcessResourceCoordinator>(connection->GetConnector()); - m_processResourceCoordinator->SetLaunchTime(base::Time::Now()); - m_processResourceCoordinator->SetPID(base::Process::Current().Pid()); - } + connection->GetConnector()->WarmService(service_manager::ServiceFilter::ByName("qtwebengine")); + m_processResourceCoordinator = std::make_unique<resource_coordinator::ProcessResourceCoordinator>(connection->GetConnector()); + m_processResourceCoordinator->OnProcessLaunched(base::Process::Current()); } } // namespace QtWebEngineCore diff --git a/src/core/browser_main_parts_qt.h b/src/core/browser_main_parts_qt.h index 04ca9483d..4eb10e379 100644 --- a/src/core/browser_main_parts_qt.h +++ b/src/core/browser_main_parts_qt.h @@ -43,7 +43,7 @@ #include "content/public/browser/browser_main_parts.h" namespace base { -class MessagePump; +class MessageLoop; } namespace content { @@ -56,8 +56,6 @@ class ProcessResourceCoordinator; namespace QtWebEngineCore { -std::unique_ptr<base::MessagePump> messagePumpFactory(); - class BrowserMainPartsQt : public content::BrowserMainParts { public: @@ -66,6 +64,7 @@ public: int PreEarlyInitialization() override; void PreMainMessageLoopStart() override; + void PreMainMessageLoopRun() override; void PostMainMessageLoopRun() override; int PreCreateThreads() override; void ServiceManagerConnectionStarted(content::ServiceManagerConnection *connection) override; @@ -73,6 +72,7 @@ public: private: DISALLOW_COPY_AND_ASSIGN(BrowserMainPartsQt); std::unique_ptr<resource_coordinator::ProcessResourceCoordinator> m_processResourceCoordinator; + std::unique_ptr<base::MessageLoop> m_mainMessageLoop; }; } // namespace QtWebEngineCore diff --git a/src/core/browser_message_filter_qt.cpp b/src/core/browser_message_filter_qt.cpp index d4fdc4122..034447512 100644 --- a/src/core/browser_message_filter_qt.cpp +++ b/src/core/browser_message_filter_qt.cpp @@ -100,7 +100,6 @@ void BrowserMessageFilterQt::OnAllowDOMStorage(int /*render_frame_id*/, void BrowserMessageFilterQt::OnAllowIndexedDB(int /*render_frame_id*/, const GURL &origin_url, const GURL &top_origin_url, - const base::string16 &/*name*/, bool *allowed) { NetworkDelegateQt *networkDelegate = static_cast<NetworkDelegateQt *>(m_profile->GetRequestContext()->GetURLRequestContext()->network_delegate()); diff --git a/src/core/browser_message_filter_qt.h b/src/core/browser_message_filter_qt.h index 8b22ab6ac..d121aa65d 100644 --- a/src/core/browser_message_filter_qt.h +++ b/src/core/browser_message_filter_qt.h @@ -73,7 +73,6 @@ private: void OnAllowIndexedDB(int render_frame_id, const GURL &origin_url, const GURL &top_origin_url, - const base::string16 &name, bool *allowed); void OnRequestFileSystemAccessSync(int render_frame_id, diff --git a/src/core/certificate_error_controller.h b/src/core/certificate_error_controller.h index 6e1e87cb0..5bea61c9b 100644 --- a/src/core/certificate_error_controller.h +++ b/src/core/certificate_error_controller.h @@ -60,7 +60,7 @@ QT_BEGIN_NAMESPACE class CertificateErrorControllerPrivate; -class QWEBENGINECORE_PRIVATE_EXPORT CertificateErrorController { +class Q_WEBENGINECORE_PRIVATE_EXPORT CertificateErrorController { public: CertificateErrorController(CertificateErrorControllerPrivate *p); ~CertificateErrorController(); diff --git a/src/core/chromium_overrides.cpp b/src/core/chromium_overrides.cpp index 841dcf4c9..c44d75a42 100644 --- a/src/core/chromium_overrides.cpp +++ b/src/core/chromium_overrides.cpp @@ -37,8 +37,6 @@ ** ****************************************************************************/ -#include "chromium_overrides.h" - #include "ozone/gl_context_qt.h" #include "qtwebenginecoreglobal_p.h" #include "web_contents_view_qt.h" @@ -52,6 +50,7 @@ #include "ui/base/dragdrop/os_exchange_data_provider_factory.h" #include "ui/events/devices/device_data_manager.h" #include "ui/events/platform/platform_event_source.h" +#include "ui/snapshot/snapshot.h" #include "ppapi/buildflags/buildflags.h" #include <QGuiApplication> @@ -59,6 +58,7 @@ #include <QWindow> #include <QFontDatabase> #include <QStringList> +#include <QLibraryInfo> #if defined(USE_AURA) && !defined(USE_OZONE) #include "ui/base/dragdrop/os_exchange_data.h" @@ -71,27 +71,6 @@ #include "net/ssl/openssl_client_key_store.h" #endif -namespace QtWebEngineCore { -void GetScreenInfoFromNativeWindow(QWindow* window, content::ScreenInfo* results) -{ - QScreen* screen = window->screen(); - if (!screen) - return; - content::ScreenInfo r; - r.device_scale_factor = screen->devicePixelRatio(); - r.depth_per_component = 8; - r.depth = screen->depth(); - r.is_monochrome = (r.depth == 1); - - QRect screenGeometry = screen->geometry(); - r.rect = gfx::Rect(screenGeometry.x(), screenGeometry.y(), screenGeometry.width(), screenGeometry.height()); - QRect available = screen->availableGeometry(); - r.available_rect = gfx::Rect(available.x(), available.y(), available.width(), available.height()); - *results = r; -} - -} // namespace QtWebEngineCore - void *GetQtXDisplay() { return GLContextHelper::getXDisplay(); @@ -112,12 +91,13 @@ WebContentsView* CreateWebContentsView(WebContentsImpl *web_contents, return rv; } -// static -void WebContentsView::GetDefaultScreenInfo(content::ScreenInfo* results) +#if defined(Q_OS_MACOS) +std::string getQtPrefix() { - QWindow dummy; - QtWebEngineCore::GetScreenInfoFromNativeWindow(&dummy, results); + const QString prefix = QLibraryInfo::location(QLibraryInfo::PrefixPath); + return prefix.toStdString(); } +#endif } // namespace content @@ -173,6 +153,53 @@ ActivationClient *GetActivationClient(aura::Window *) } // namespace wm #endif // defined(USE_AURA) || defined(USE_OZONE) +#if defined(USE_AURA) +namespace ui { + +bool GrabWindowSnapshot(gfx::NativeWindow window, + const gfx::Rect& snapshot_bounds, + gfx::Image* image) +{ + NOTIMPLEMENTED(); + return false; +} + +bool GrabViewSnapshot(gfx::NativeView view, + const gfx::Rect& snapshot_bounds, + gfx::Image* image) +{ + NOTIMPLEMENTED(); + return false; +} + +void GrabWindowSnapshotAndScaleAsync(gfx::NativeWindow window, + const gfx::Rect& source_rect, + const gfx::Size& target_size, + const GrabWindowSnapshotAsyncCallback& callback) +{ + NOTIMPLEMENTED(); + callback.Run(gfx::Image()); +} + +void GrabWindowSnapshotAsync(gfx::NativeWindow window, + const gfx::Rect& source_rect, + const GrabWindowSnapshotAsyncCallback& callback) +{ + NOTIMPLEMENTED(); + callback.Run(gfx::Image()); +} + +void GrabViewSnapshotAsync(gfx::NativeView view, + const gfx::Rect& source_rect, + const GrabWindowSnapshotAsyncCallback& callback) +{ + NOTIMPLEMENTED(); + callback.Run(gfx::Image()); +} + +} // namespace ui +#endif // defined(USE_AURA) + std::unique_ptr<ui::OSExchangeData::Provider> ui::OSExchangeDataProviderFactory::CreateProvider() { return nullptr; diff --git a/src/core/client_cert_select_controller.cpp b/src/core/client_cert_select_controller.cpp index 7d08d57c1..0baaf2bc5 100644 --- a/src/core/client_cert_select_controller.cpp +++ b/src/core/client_cert_select_controller.cpp @@ -48,6 +48,8 @@ #include "type_conversion.h" +#include <QDebug> + QT_BEGIN_NAMESPACE using namespace QtWebEngineCore; @@ -76,17 +78,40 @@ ClientCertSelectController::~ClientCertSelectController() void ClientCertSelectController::selectNone() { if (m_selected) { - qWarning() << "ClientCertSelectController::selectNone() certicate already selected"; + LOG(WARNING) << "ClientCertSelectController::selectNone() certificate already selected"; return; } m_selected = true; m_delegate->ContinueWithCertificate(nullptr, nullptr); } +void ClientCertSelectController::select(int index) +{ + if (m_selected) { + LOG(WARNING) << "ClientCertSelectController::select() certificate already selected"; + return; + } + for (auto &certInfo : m_clientCerts) { + if (index == 0) { + m_selected = true; + scoped_refptr<net::X509Certificate> cert = certInfo->certificate(); + net::ClientCertIdentity::SelfOwningAcquirePrivateKey( + std::move(certInfo), + base::Bind(&content::ClientCertificateDelegate::ContinueWithCertificate, + base::Passed(std::move(m_delegate)), std::move(cert))); + return; + } + std::vector<std::string> pem_encoded; + if (certInfo->certificate()->GetPEMEncodedChain(&pem_encoded)) + --index; + } + LOG(WARNING) << "ClientCertSelectController::select() index out of range:" << index; +} + void ClientCertSelectController::select(const QSslCertificate &certificate) { if (m_selected) { - qWarning() << "ClientCertSelectController::select() certicate already selected"; + LOG(WARNING) << "ClientCertSelectController::select() certificate already selected"; return; } QByteArray derCertificate = certificate.toDer(); @@ -103,19 +128,20 @@ void ClientCertSelectController::select(const QSslCertificate &certificate) return; } } - qWarning() << "ClientCertSelectController::select() - selected client certificate not recognized." - << " Selected certificate needs to be one of the offered"; + LOG(WARNING) << "ClientCertSelectController::select() - selected client certificate not recognized." + << " Selected certificate needs to be one of the offered"; } QVector<QSslCertificate> ClientCertSelectController::certificates() const { - QVector<QSslCertificate> out; + if (!m_certificates.isEmpty()) + return m_certificates; for (auto &cert : m_clientCerts) { std::vector<std::string> pem_encoded; if (cert->certificate()->GetPEMEncodedChain(&pem_encoded)) - out.append(QSslCertificate(QByteArray::fromStdString(pem_encoded.front()))); + m_certificates.append(QSslCertificate(QByteArray::fromStdString(pem_encoded.front()))); } - return out; + return m_certificates; } #endif // !defined(QT_NO_SSL) || QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) diff --git a/src/core/client_cert_select_controller.h b/src/core/client_cert_select_controller.h index 46324ee90..f121c1155 100644 --- a/src/core/client_cert_select_controller.h +++ b/src/core/client_cert_select_controller.h @@ -72,7 +72,7 @@ class SSLCertRequestInfo; QT_BEGIN_NAMESPACE -class QWEBENGINECORE_PRIVATE_EXPORT ClientCertSelectController { +class Q_WEBENGINECORE_PRIVATE_EXPORT ClientCertSelectController { public: ClientCertSelectController(net::SSLCertRequestInfo *certRequestInfo, std::vector<std::unique_ptr<net::ClientCertIdentity>> clientCerts, @@ -83,6 +83,7 @@ public: #if !defined(QT_NO_SSL) || QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) void selectNone(); void select(const QSslCertificate &certificate); + void select(int index); QVector<QSslCertificate> certificates() const; #endif @@ -91,6 +92,7 @@ private: QUrl m_hostAndPort; std::vector<std::unique_ptr<net::ClientCertIdentity>> m_clientCerts; std::unique_ptr<content::ClientCertificateDelegate> m_delegate; + mutable QVector<QSslCertificate> m_certificates; bool m_selected; }; diff --git a/src/core/clipboard_change_observer.h b/src/core/clipboard_change_observer.h new file mode 100644 index 000000000..f9b33fc93 --- /dev/null +++ b/src/core/clipboard_change_observer.h @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CLIPBOARD_CHANGE_OBSERVER_H +#define CLIPBOARD_CHANGE_OBSERVER_H + +#include <QClipboard> +#include <QMap> +#include <QObject> + +namespace QtWebEngineCore { + +class ClipboardChangeObserver : public QObject { + Q_OBJECT +public: + ClipboardChangeObserver(); + quint64 getSequenceNumber(QClipboard::Mode mode) { return sequenceNumber.value(mode); } + +private Q_SLOTS: + void trackChange(QClipboard::Mode mode); + +private: + QMap<QClipboard::Mode, quint64> sequenceNumber; +}; + +} // namespace QtWebEngineCore + +#endif // CLIPBOARD_CHANGE_OBSERVER_H diff --git a/src/core/clipboard_qt.cpp b/src/core/clipboard_qt.cpp index 44756bdfe..f4a14570a 100644 --- a/src/core/clipboard_qt.cpp +++ b/src/core/clipboard_qt.cpp @@ -42,13 +42,15 @@ // found in the LICENSE.Chromium file. #include "clipboard_qt.h" -#include "ui/base/clipboard/clipboard.h" - +#include "clipboard_change_observer.h" #include "type_conversion.h" #include "base/logging.h" #include "third_party/skia/include/core/SkBitmap.h" #include "ui/base/clipboard/custom_data_helper.h" +#include "ui/base/clipboard/clipboard.h" +#include "ui/base/clipboard/clipboard_constants.h" +#include "ui/base/clipboard/clipboard_format_type.h" #include <QGuiApplication> #include <QImage> @@ -81,12 +83,6 @@ using namespace QtWebEngineCore; namespace { -const char kMimeTypeBitmap[] = "image/bmp"; -const char kMimeTypeMozillaURL[] = "text/x-moz-url"; -const char kMimeTypeWebCustomDataCopy[] = "chromium/x-web-custom-data"; -const char kMimeTypePepperCustomData[] = "chromium/x-pepper-custom-data"; -const char kMimeTypeWebkitSmartPaste[] = "chromium/x-webkit-paste"; - QScopedPointer<QMimeData> uncommittedData; QMimeData *getUncommittedData() { @@ -95,118 +91,21 @@ QMimeData *getUncommittedData() return uncommittedData.data(); } -} // namespace +} // namespace namespace ui { // Factory function -Clipboard* Clipboard::Create() { - return new ClipboardQt; -} - -Clipboard::FormatType Clipboard::GetFormatType(const std::string& format_string) -{ - return FormatType::Deserialize(format_string); -} - -const Clipboard::FormatType& Clipboard::GetPlainTextFormatType() -{ - CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeText)); - return type; -} - -const Clipboard::FormatType& Clipboard::GetPlainTextWFormatType() -{ - return GetPlainTextFormatType(); -} - -const Clipboard::FormatType& Clipboard::GetUrlFormatType() -{ - return GetPlainTextFormatType(); -} - -const Clipboard::FormatType& Clipboard::GetUrlWFormatType() -{ - return GetPlainTextWFormatType(); -} - -const Clipboard::FormatType& Clipboard::GetHtmlFormatType() -{ - CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeHTML)); - return type; -} - -const Clipboard::FormatType& Clipboard::GetRtfFormatType() -{ - CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeRTF)); - return type; -} - -const Clipboard::FormatType& Clipboard::GetBitmapFormatType() -{ - CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeBitmap)); - return type; -} - -const Clipboard::FormatType& Clipboard::GetWebKitSmartPasteFormatType() +Clipboard *Clipboard::Create() { - CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeWebkitSmartPaste)); - return type; -} - -const Clipboard::FormatType& Clipboard::GetWebCustomDataFormatType() -{ - CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeWebCustomDataCopy)); - return type; -} - -const Clipboard::FormatType& Clipboard::GetPepperCustomDataFormatType() -{ - CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypePepperCustomData)); - return type; -} - - -Clipboard::FormatType::FormatType() -{ -} - -Clipboard::FormatType::FormatType(const std::string& format_string) - : data_(format_string) -{ -} - -Clipboard::FormatType::~FormatType() -{ -} - -std::string Clipboard::FormatType::Serialize() const -{ - return data_; -} - -Clipboard::FormatType Clipboard::FormatType::Deserialize(const std::string& serialization) -{ - return FormatType(serialization); -} - -bool Clipboard::FormatType::Equals(const FormatType& other) const -{ - return data_ == other.data_; -} - -#if defined(OS_WIN) || defined(USE_AURA) -bool Clipboard::FormatType::operator<(const FormatType& other) const -{ - return data_.compare(other.data_) < 0; + return new ClipboardQt; } -#endif } // namespace ui namespace QtWebEngineCore { -void ClipboardQt::WriteObjects(ui::ClipboardType type, const ObjectMap& objects) +void ClipboardQt::WriteObjects(ui::ClipboardType type, const ObjectMap &objects) { DCHECK(CalledOnValidThread()); DCHECK(IsSupportedClipboardType(type)); @@ -216,7 +115,9 @@ void ClipboardQt::WriteObjects(ui::ClipboardType type, const ObjectMap& objects) // Commit the accumulated data. if (uncommittedData) - QGuiApplication::clipboard()->setMimeData(uncommittedData.take(), type == ui::CLIPBOARD_TYPE_COPY_PASTE ? QClipboard::Clipboard : QClipboard::Selection); + QGuiApplication::clipboard()->setMimeData(uncommittedData.take(), + type == ui::CLIPBOARD_TYPE_COPY_PASTE ? QClipboard::Clipboard + : QClipboard::Selection); if (type == ui::CLIPBOARD_TYPE_COPY_PASTE && IsSupportedClipboardType(ui::CLIPBOARD_TYPE_SELECTION)) { ObjectMap::const_iterator text_iter = objects.find(CBF_TEXT); @@ -228,32 +129,32 @@ void ClipboardQt::WriteObjects(ui::ClipboardType type, const ObjectMap& objects) } } -void ClipboardQt::WriteText(const char* text_data, size_t text_len) +void ClipboardQt::WriteText(const char *text_data, size_t text_len) { getUncommittedData()->setText(QString::fromUtf8(text_data, text_len)); } -void ClipboardQt::WriteHTML(const char* markup_data, size_t markup_len, const char* url_data, size_t url_len) +void ClipboardQt::WriteHTML(const char *markup_data, size_t markup_len, const char *url_data, size_t url_len) { getUncommittedData()->setHtml(QString::fromUtf8(markup_data, markup_len)); } -void ClipboardQt::WriteRTF(const char* rtf_data, size_t data_len) +void ClipboardQt::WriteRTF(const char *rtf_data, size_t data_len) { - getUncommittedData()->setData(QString::fromLatin1(kMimeTypeRTF), QByteArray(rtf_data, data_len)); + getUncommittedData()->setData(QString::fromLatin1(ui::kMimeTypeRTF), QByteArray(rtf_data, data_len)); } void ClipboardQt::WriteWebSmartPaste() { - getUncommittedData()->setData(QString::fromLatin1(kMimeTypeWebkitSmartPaste), QByteArray()); + getUncommittedData()->setData(QString::fromLatin1(ui::kMimeTypeWebkitSmartPaste), QByteArray()); } -void ClipboardQt::WriteBitmap(const SkBitmap& bitmap) +void ClipboardQt::WriteBitmap(const SkBitmap &bitmap) { getUncommittedData()->setImageData(toQImage(bitmap).copy()); } -void ClipboardQt::WriteBookmark(const char* title_data, size_t title_len, const char* url_data, size_t url_len) +void ClipboardQt::WriteBookmark(const char *title_data, size_t title_len, const char *url_data, size_t url_len) { // FIXME: Untested, seems to be used only for drag-n-drop. // Write as a mozilla url (UTF16: URL, newline, title). @@ -261,29 +162,32 @@ void ClipboardQt::WriteBookmark(const char* title_data, size_t title_len, const QString title = QString::fromUtf8(title_data, title_len); QByteArray data; - data.append(reinterpret_cast<const char*>(url.utf16()), url.size() * 2); + data.append(reinterpret_cast<const char *>(url.utf16()), url.size() * 2); data.append('\n'); - data.append(reinterpret_cast<const char*>(title.utf16()), title.size() * 2); - getUncommittedData()->setData(QString::fromLatin1(kMimeTypeMozillaURL), data); + data.append(reinterpret_cast<const char *>(title.utf16()), title.size() * 2); + getUncommittedData()->setData(QString::fromLatin1(ui::kMimeTypeMozillaURL), data); } -void ClipboardQt::WriteData(const FormatType& format, const char* data_data, size_t data_len) +void ClipboardQt::WriteData(const ui::ClipboardFormatType &format, const char *data_data, size_t data_len) { getUncommittedData()->setData(QString::fromStdString(format.ToString()), QByteArray(data_data, data_len)); } -bool ClipboardQt::IsFormatAvailable(const ui::Clipboard::FormatType& format, ui::ClipboardType type) const +bool ClipboardQt::IsFormatAvailable(const ui::ClipboardFormatType &format, ui::ClipboardType type) const { - const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData(type == ui::CLIPBOARD_TYPE_COPY_PASTE ? QClipboard::Clipboard : QClipboard::Selection); + const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData( + type == ui::CLIPBOARD_TYPE_COPY_PASTE ? QClipboard::Clipboard : QClipboard::Selection); return mimeData && mimeData->hasFormat(QString::fromStdString(format.ToString())); } void ClipboardQt::Clear(ui::ClipboardType type) { - QGuiApplication::clipboard()->clear(type == ui::CLIPBOARD_TYPE_COPY_PASTE ? QClipboard::Clipboard : QClipboard::Selection); + QGuiApplication::clipboard()->clear(type == ui::CLIPBOARD_TYPE_COPY_PASTE ? QClipboard::Clipboard + : QClipboard::Selection); } -void ClipboardQt::ReadAvailableTypes(ui::ClipboardType type, std::vector<base::string16>* types, bool* contains_filenames) const +void ClipboardQt::ReadAvailableTypes(ui::ClipboardType type, std::vector<base::string16> *types, + bool *contains_filenames) const { if (!types || !contains_filenames) { NOTREACHED(); @@ -291,7 +195,8 @@ void ClipboardQt::ReadAvailableTypes(ui::ClipboardType type, std::vector<base::s } types->clear(); - const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData(type == ui::CLIPBOARD_TYPE_COPY_PASTE ? QClipboard::Clipboard : QClipboard::Selection); + const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData( + type == ui::CLIPBOARD_TYPE_COPY_PASTE ? QClipboard::Clipboard : QClipboard::Selection); if (!mimeData) return; if (mimeData->hasImage() && !mimeData->formats().contains(QStringLiteral("image/png"))) @@ -301,26 +206,28 @@ void ClipboardQt::ReadAvailableTypes(ui::ClipboardType type, std::vector<base::s types->push_back(toString16(mimeType)); *contains_filenames = false; - const QByteArray customData = mimeData->data(QString::fromLatin1(kMimeTypeWebCustomDataCopy)); + const QByteArray customData = mimeData->data(QString::fromLatin1(ui::kMimeTypeWebCustomData)); ui::ReadCustomDataTypes(customData.constData(), customData.size(), types); } - -void ClipboardQt::ReadText(ui::ClipboardType type, base::string16* result) const +void ClipboardQt::ReadText(ui::ClipboardType type, base::string16 *result) const { - const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData(type == ui::CLIPBOARD_TYPE_COPY_PASTE ? QClipboard::Clipboard : QClipboard::Selection); + const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData( + type == ui::CLIPBOARD_TYPE_COPY_PASTE ? QClipboard::Clipboard : QClipboard::Selection); if (mimeData) *result = toString16(mimeData->text()); } -void ClipboardQt::ReadAsciiText(ui::ClipboardType type, std::string* result) const +void ClipboardQt::ReadAsciiText(ui::ClipboardType type, std::string *result) const { - const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData(type == ui::CLIPBOARD_TYPE_COPY_PASTE ? QClipboard::Clipboard : QClipboard::Selection); + const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData( + type == ui::CLIPBOARD_TYPE_COPY_PASTE ? QClipboard::Clipboard : QClipboard::Selection); if (mimeData) *result = mimeData->text().toStdString(); } -void ClipboardQt::ReadHTML(ui::ClipboardType type, base::string16* markup, std::string* src_url, uint32_t* fragment_start, uint32_t* fragment_end) const +void ClipboardQt::ReadHTML(ui::ClipboardType type, base::string16 *markup, std::string *src_url, + uint32_t *fragment_start, uint32_t *fragment_end) const { markup->clear(); if (src_url) @@ -328,25 +235,28 @@ void ClipboardQt::ReadHTML(ui::ClipboardType type, base::string16* markup, std:: *fragment_start = 0; *fragment_end = 0; - const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData(type == ui::CLIPBOARD_TYPE_COPY_PASTE ? QClipboard::Clipboard : QClipboard::Selection); + const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData( + type == ui::CLIPBOARD_TYPE_COPY_PASTE ? QClipboard::Clipboard : QClipboard::Selection); if (!mimeData) return; *markup = toString16(mimeData->html()); *fragment_end = static_cast<uint32_t>(markup->length()); } -void ClipboardQt::ReadRTF(ui::ClipboardType type, std::string* result) const +void ClipboardQt::ReadRTF(ui::ClipboardType type, std::string *result) const { - const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData(type == ui::CLIPBOARD_TYPE_COPY_PASTE ? QClipboard::Clipboard : QClipboard::Selection); + const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData( + type == ui::CLIPBOARD_TYPE_COPY_PASTE ? QClipboard::Clipboard : QClipboard::Selection); if (!mimeData) return; - const QByteArray byteArray = mimeData->data(QString::fromLatin1(kMimeTypeRTF)); + const QByteArray byteArray = mimeData->data(QString::fromLatin1(ui::kMimeTypeRTF)); *result = std::string(byteArray.constData(), byteArray.length()); } SkBitmap ClipboardQt::ReadImage(ui::ClipboardType type) const { - const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData(type == ui::CLIPBOARD_TYPE_COPY_PASTE ? QClipboard::Clipboard : QClipboard::Selection); + const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData( + type == ui::CLIPBOARD_TYPE_COPY_PASTE ? QClipboard::Clipboard : QClipboard::Selection); if (!mimeData) return SkBitmap(); QImage image = qvariant_cast<QImage>(mimeData->imageData()); @@ -369,21 +279,22 @@ SkBitmap ClipboardQt::ReadImage(ui::ClipboardType type) const return bitmap; } -void ClipboardQt::ReadCustomData(ui::ClipboardType clipboard_type, const base::string16& type, base::string16* result) const +void ClipboardQt::ReadCustomData(ui::ClipboardType clipboard_type, const base::string16 &type, base::string16 *result) const { - const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData(clipboard_type == ui::CLIPBOARD_TYPE_COPY_PASTE ? QClipboard::Clipboard : QClipboard::Selection); + const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData( + clipboard_type == ui::CLIPBOARD_TYPE_COPY_PASTE ? QClipboard::Clipboard : QClipboard::Selection); if (!mimeData) return; - const QByteArray customData = mimeData->data(QString::fromLatin1(kMimeTypeWebCustomDataCopy)); + const QByteArray customData = mimeData->data(QString::fromLatin1(ui::kMimeTypeWebCustomData)); ui::ReadCustomDataForType(customData.constData(), customData.size(), type, result); } -void ClipboardQt::ReadBookmark(base::string16* title, std::string* url) const +void ClipboardQt::ReadBookmark(base::string16 *title, std::string *url) const { NOTIMPLEMENTED(); } -void ClipboardQt::ReadData(const FormatType& format, std::string* result) const +void ClipboardQt::ReadData(const ui::ClipboardFormatType &format, std::string *result) const { const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData(); if (!mimeData) @@ -394,7 +305,8 @@ void ClipboardQt::ReadData(const FormatType& format, std::string* result) const uint64_t ClipboardQt::GetSequenceNumber(ui::ClipboardType type) const { - return clipboardChangeObserver()->getSequenceNumber(type == ui::CLIPBOARD_TYPE_COPY_PASTE ? QClipboard::Clipboard : QClipboard::Selection); + return clipboardChangeObserver()->getSequenceNumber(type == ui::CLIPBOARD_TYPE_COPY_PASTE ? QClipboard::Clipboard + : QClipboard::Selection); } -} // namespace QtWebEngineCore +} // namespace QtWebEngineCore diff --git a/src/core/clipboard_qt.h b/src/core/clipboard_qt.h index 2089208bf..7884da167 100644 --- a/src/core/clipboard_qt.h +++ b/src/core/clipboard_qt.h @@ -42,57 +42,36 @@ #include "ui/base/clipboard/clipboard.h" -#include <QClipboard> -#include <QMap> -#include <QObject> - namespace QtWebEngineCore { -class ClipboardChangeObserver : public QObject { - Q_OBJECT -public: - ClipboardChangeObserver(); - quint64 getSequenceNumber(QClipboard::Mode mode) { - return sequenceNumber.value(mode); - } - -private Q_SLOTS: - void trackChange(QClipboard::Mode mode); - -private: - QMap<QClipboard::Mode, quint64> sequenceNumber; -}; - class ClipboardQt : public ui::Clipboard { public: uint64_t GetSequenceNumber(ui::ClipboardType type) const override; - bool IsFormatAvailable(const FormatType& format, ui::ClipboardType type) const override; + bool IsFormatAvailable(const ui::ClipboardFormatType &format, ui::ClipboardType type) const override; void Clear(ui::ClipboardType type) override; - void ReadAvailableTypes(ui::ClipboardType type, std::vector<base::string16>* types, bool* contains_filenames) const override; - void ReadText(ui::ClipboardType type, base::string16* result) const override; - void ReadAsciiText(ui::ClipboardType type, std::string* result) const override; - void ReadHTML(ui::ClipboardType type, - base::string16* markup, - std::string* src_url, - uint32_t* fragment_start, - uint32_t* fragment_end) const override; - void ReadRTF(ui::ClipboardType type, std::string* result) const override; + void ReadAvailableTypes(ui::ClipboardType type, std::vector<base::string16> *types, + bool *contains_filenames) const override; + void ReadText(ui::ClipboardType type, base::string16 *result) const override; + void ReadAsciiText(ui::ClipboardType type, std::string *result) const override; + void ReadHTML(ui::ClipboardType type, base::string16 *markup, std::string *src_url, uint32_t *fragment_start, + uint32_t *fragment_end) const override; + void ReadRTF(ui::ClipboardType type, std::string *result) const override; SkBitmap ReadImage(ui::ClipboardType type) const override; - void ReadCustomData(ui::ClipboardType clipboard_type, const base::string16& type, base::string16* result) const override; - void ReadBookmark(base::string16* title, std::string* url) const override; - void ReadData(const FormatType& format, std::string* result) const override; + void ReadCustomData(ui::ClipboardType clipboard_type, const base::string16 &type, base::string16 *result) const override; + void ReadBookmark(base::string16 *title, std::string *url) const override; + void ReadData(const ui::ClipboardFormatType &format, std::string *result) const override; - void OnPreShutdown() override { } + void OnPreShutdown() override {} protected: - void WriteObjects(ui::ClipboardType type, const ObjectMap& objects) override; - void WriteText(const char* text_data, size_t text_len) override; - void WriteHTML(const char* markup_data, size_t markup_len, const char* url_data, size_t url_len) override; - void WriteRTF(const char* rtf_data, size_t data_len) override; - void WriteBookmark(const char* title_data, size_t title_len, const char* url_data, size_t url_len) override; + void WriteObjects(ui::ClipboardType type, const ObjectMap &objects) override; + void WriteText(const char *text_data, size_t text_len) override; + void WriteHTML(const char *markup_data, size_t markup_len, const char *url_data, size_t url_len) override; + void WriteRTF(const char *rtf_data, size_t data_len) override; + void WriteBookmark(const char *title_data, size_t title_len, const char *url_data, size_t url_len) override; void WriteWebSmartPaste() override; - void WriteBitmap(const SkBitmap& bitmap) override; - void WriteData(const FormatType& format, const char* data_data, size_t data_len) override; + void WriteBitmap(const SkBitmap &bitmap) override; + void WriteData(const ui::ClipboardFormatType &format, const char *data_data, size_t data_len) override; }; } // namespace QtWebEngineCore diff --git a/src/core/color_chooser_controller.cpp b/src/core/color_chooser_controller.cpp index 26d675908..361ff93ba 100644 --- a/src/core/color_chooser_controller.cpp +++ b/src/core/color_chooser_controller.cpp @@ -43,6 +43,9 @@ #include "color_chooser_controller_p.h" #include "type_conversion.h" +#include <QColor> +#include <QVariant> + namespace QtWebEngineCore { ColorChooserControllerPrivate::ColorChooserControllerPrivate(content::WebContents *content, const QColor &color) diff --git a/src/core/color_chooser_controller.h b/src/core/color_chooser_controller.h index 4c1b81a9a..66222bb77 100644 --- a/src/core/color_chooser_controller.h +++ b/src/core/color_chooser_controller.h @@ -55,11 +55,14 @@ #include <QObject> +QT_FORWARD_DECLARE_CLASS(QColor) +QT_FORWARD_DECLARE_CLASS(QVariant) + namespace QtWebEngineCore { class ColorChooserControllerPrivate; -class QWEBENGINECORE_PRIVATE_EXPORT ColorChooserController : public QObject { +class Q_WEBENGINECORE_PRIVATE_EXPORT ColorChooserController : public QObject { Q_OBJECT public: ~ColorChooserController(); diff --git a/src/core/command_line_pref_store_qt.cpp b/src/core/command_line_pref_store_qt.cpp new file mode 100644 index 000000000..5c5c82e1a --- /dev/null +++ b/src/core/command_line_pref_store_qt.cpp @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "command_line_pref_store_qt.h" + +#include "chrome/common/chrome_switches.h" +#include "components/proxy_config/proxy_config_dictionary.h" +#include "components/proxy_config/proxy_config_pref_names.h" +#include "content/public/common/content_switches.h" +#include <QDebug> + +CommandLinePrefStoreQt::CommandLinePrefStoreQt(const base::CommandLine *commandLine) + : CommandLinePrefStore(commandLine) +{ + + if (commandLine->HasSwitch(switches::kNoProxyServer)) { + SetValue(proxy_config::prefs::kProxy, + std::make_unique<base::Value>(ProxyConfigDictionary::CreateDirect()), + WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS); + } else if (commandLine->HasSwitch(switches::kProxyPacUrl)) { + std::string pac_script_url = + commandLine->GetSwitchValueASCII(switches::kProxyPacUrl); + SetValue(proxy_config::prefs::kProxy, + std::make_unique<base::Value>(ProxyConfigDictionary::CreatePacScript( + pac_script_url, false)), + WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS); + } else if (commandLine->HasSwitch(switches::kProxyAutoDetect)) { + SetValue(proxy_config::prefs::kProxy, + std::make_unique<base::Value>( + ProxyConfigDictionary::CreateAutoDetect()), + WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS); + } else if (commandLine->HasSwitch(switches::kProxyServer)) { + std::string proxy_server = + commandLine->GetSwitchValueASCII(switches::kProxyServer); + std::string bypass_list = + commandLine->GetSwitchValueASCII(switches::kProxyBypassList); + SetValue( + proxy_config::prefs::kProxy, + std::make_unique<base::Value>(ProxyConfigDictionary::CreateFixedServers( + proxy_server, bypass_list)), + WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS); + } + + if (commandLine->HasSwitch(switches::kNoProxyServer) && (commandLine->HasSwitch(switches::kProxyAutoDetect) || commandLine->HasSwitch(switches::kProxyServer) || commandLine->HasSwitch(switches::kProxyPacUrl) || commandLine->HasSwitch(switches::kProxyBypassList))) { + qWarning("Additional command-line proxy switches specified when --%s was also specified", + qPrintable(switches::kNoProxyServer)); + } +} + +CommandLinePrefStoreQt::~CommandLinePrefStoreQt() = default; diff --git a/src/core/command_line_pref_store_qt.h b/src/core/command_line_pref_store_qt.h new file mode 100644 index 000000000..a509f8ca9 --- /dev/null +++ b/src/core/command_line_pref_store_qt.h @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef COMMAND_LINE_PREF_STORE_QT_H +#define COMMAND_LINE_PREF_STORE_QT_H + +#include "base/command_line.h" +#include "components/prefs/command_line_pref_store.h" + +class CommandLinePrefStoreQt : public CommandLinePrefStore +{ +public: + explicit CommandLinePrefStoreQt(const base::CommandLine *commandLine); + +protected: + ~CommandLinePrefStoreQt() override; + DISALLOW_COPY_AND_ASSIGN(CommandLinePrefStoreQt); +}; + +#endif // COMMAND_LINE_PREF_STORE_QT_H diff --git a/src/core/common/extensions/api/qtwebengine_extensions_features.gni b/src/core/common/extensions/api/qtwebengine_extensions_features.gni new file mode 100644 index 000000000..ed7e713c6 --- /dev/null +++ b/src/core/common/extensions/api/qtwebengine_extensions_features.gni @@ -0,0 +1,25 @@ +import("//tools/json_schema_compiler/json_features.gni") + +json_features("qt_api_features") { + feature_type = "APIFeature" + method_name = "AddQtAPIFeatures" + sources = [ + "//extensions/common/api/_webengine_api_features.json" + ] +} + +json_features("qt_permission_features") { + feature_type = "PermissionFeature" + method_name = "AddQtPermissionFeatures" + sources = [ + "//extensions/common/api/_permission_features.json" + ] +} + +group("qtwebengine_extensions_features") { + public_deps = [ + ":qt_api_features", + ":qt_permission_features", + "//extensions/common/api:extensions_features", + ] +} diff --git a/src/core/common/extensions/extensions_api_provider_qt.cpp b/src/core/common/extensions/extensions_api_provider_qt.cpp new file mode 100644 index 000000000..22154a9d1 --- /dev/null +++ b/src/core/common/extensions/extensions_api_provider_qt.cpp @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "extensions_api_provider_qt.h" + +#include "chrome/grit/common_resources.h" + +#include "extensions/common/api/api_features.h" +#include "extensions/common/api/behavior_features.h" +#include "extensions/common/api/generated_schemas.h" +#include "extensions/common/api/manifest_features.h" +#include "extensions/common/api/permission_features.h" +#include "extensions/common/common_manifest_handlers.h" +#include "extensions/common/features/feature_provider.h" +#include "extensions/common/features/json_feature_provider_source.h" +#include "extensions/common/permissions/permissions_info.h" +#include "extensions/grit/extensions_resources.h" + +#include "qt_api_features.h" +//#include "qt_behavior_features.h" +#include "qt_permission_features.h" +//#include "qt_manifest_features.h" + + +namespace extensions { + +ExtensionsAPIProviderQt::ExtensionsAPIProviderQt() +{ +} + +void ExtensionsAPIProviderQt::RegisterManifestHandlers() +{ +} + +void ExtensionsAPIProviderQt::AddAPIFeatures(FeatureProvider *provider) +{ + AddQtAPIFeatures(provider); +} + +void ExtensionsAPIProviderQt::AddAPIJSONSources(JSONFeatureProviderSource *json_source) +{ + json_source->LoadJSON(IDR_CHROME_EXTENSION_API_FEATURES); +} + +void ExtensionsAPIProviderQt::AddPermissionFeatures(FeatureProvider *provider) +{ + AddQtPermissionFeatures(provider); +} + +bool ExtensionsAPIProviderQt::IsAPISchemaGenerated(const std::string &name) +{ + return api::GeneratedSchemas::IsGenerated(name); +} + +base::StringPiece ExtensionsAPIProviderQt::GetAPISchema(const std::string &name) +{ + return api::GeneratedSchemas::Get(name); +} + +void ExtensionsAPIProviderQt::RegisterPermissions(PermissionsInfo* permissions_info) +{ +} + +} diff --git a/src/core/common/extensions/extensions_api_provider_qt.h b/src/core/common/extensions/extensions_api_provider_qt.h new file mode 100644 index 000000000..7d8c5f98b --- /dev/null +++ b/src/core/common/extensions/extensions_api_provider_qt.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef EXTENSIONS_API_PROVIDER_QT_H +#define EXTENSIONS_API_PROVIDER_QT_H + +#include "extensions/common/extensions_api_provider.h" + +#include "base/macros.h" + +namespace extensions { + +class ExtensionsAPIProviderQt : public ExtensionsAPIProvider +{ +public: + ExtensionsAPIProviderQt(); + + void RegisterManifestHandlers() override; + void AddAPIFeatures(FeatureProvider *provider) override; + void AddAPIJSONSources(JSONFeatureProviderSource* json_source) override; + void AddPermissionFeatures(FeatureProvider* provider) override; + + bool IsAPISchemaGenerated(const std::string& name) override; + base::StringPiece GetAPISchema(const std::string& name) override; + + // Adds feature definitions to the given |provider| of the specified type. + void AddManifestFeatures(FeatureProvider* provider) override { } + void AddBehaviorFeatures(FeatureProvider* provider) override { } + + // Registers permissions for any associated API features. + void RegisterPermissions(PermissionsInfo* permissions_info) override; + +DISALLOW_COPY_AND_ASSIGN(ExtensionsAPIProviderQt); +}; + +} + +#endif // EXTENSIONS_API_PROVIDER_QT_H diff --git a/src/core/common/extensions/extensions_client_qt.cpp b/src/core/common/extensions/extensions_client_qt.cpp new file mode 100644 index 000000000..6c6200eb0 --- /dev/null +++ b/src/core/common/extensions/extensions_client_qt.cpp @@ -0,0 +1,190 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// Portions copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "extensions_client_qt.h" + +#include "extensions/common/alias.h" +#include "extensions/common/core_extensions_api_provider.h" +#include "extensions/common/extension_urls.h" + +#include "extensions/common/features/simple_feature.h" +#include "extensions/common/permissions/permissions_info.h" + +#include "extensions_api_provider_qt.h" + + +namespace extensions { + +template<class FeatureClass> SimpleFeature *CreateFeature() +{ + return new FeatureClass; +} + +static base::LazyInstance<ExtensionsClientQt>::Leaky g_client = LAZY_INSTANCE_INITIALIZER; + +ExtensionsClientQt *ExtensionsClientQt::GetInstance() +{ + return g_client.Pointer(); +} + +ExtensionsClientQt::ExtensionsClientQt() : ExtensionsClient() +{ + AddAPIProvider(std::make_unique<CoreExtensionsAPIProvider>()); + AddAPIProvider(std::make_unique<ExtensionsAPIProviderQt>()); +} + +// Initializes global state. Not done in the constructor because unit tests +// can create additional ExtensionsClients because the utility thread runs +// in-process. +void ExtensionsClientQt::Initialize() +{ +} + +void ExtensionsClientQt::InitializeWebStoreUrls(base::CommandLine *command_line) +{ +} + +// Returns the global PermissionMessageProvider to use to provide permission +// warning strings. +const PermissionMessageProvider &ExtensionsClientQt::GetPermissionMessageProvider() const +{ + return permission_message_provider_; +} + +// Returns the application name. For example, "Chromium" or "app_shell". +const std::string ExtensionsClientQt::GetProductName() +{ + return "Qt WebEngine"; // return Qt WebEngine for now, consider returning the application name if possible. +} + +// Takes the list of all hosts and filters out those with special +// permission strings. Adds the regular hosts to |new_hosts|, +// and adds any additional permissions to |permissions|. +// TODO(sashab): Split this function in two: One to filter out ignored host +// permissions, and one to get permissions for the given hosts. +void ExtensionsClientQt::FilterHostPermissions(const URLPatternSet &hosts, + URLPatternSet *new_hosts, + PermissionIDSet *permissions) const +{ +} + +// Replaces the scripting whitelist with |whitelist|. Used in the renderer{} +// only used for testing in the browser process. +void ExtensionsClientQt::SetScriptingWhitelist(const ExtensionsClient::ScriptingWhitelist &whitelist) +{ + scripting_whitelist_ = whitelist; +} + +// Return the whitelist of extensions that can run content scripts on +// any origin. +const ExtensionsClient::ScriptingWhitelist &ExtensionsClientQt::GetScriptingWhitelist() const +{ + return scripting_whitelist_; +} + +// Get the set of chrome:// hosts that |extension| can run content scripts on. +URLPatternSet ExtensionsClientQt::GetPermittedChromeSchemeHosts(const Extension *extension, + const APIPermissionSet &api_permissions) const +{ + return URLPatternSet(); +} + +// Returns false if content scripts are forbidden from running on |url|. +bool ExtensionsClientQt::IsScriptableURL(const GURL &url, std::string *error) const +{ + return true; +} + +// Determines if certain fatal extensions errors should be surpressed +// (i.e., only logged) or allowed (i.e., logged before crashing). +bool ExtensionsClientQt::ShouldSuppressFatalErrors() const +{ + return true; +} + +// Records that a fatal error was caught and suppressed. It is expected that +// embedders will only do so if ShouldSuppressFatalErrors at some point +// returned true. +void ExtensionsClientQt::RecordDidSuppressFatalError() +{ +} + +// Returns the base webstore URL prefix. +const GURL &ExtensionsClientQt::GetWebstoreBaseURL() const +{ + if (base_url_.is_empty()) + base_url_ = GURL(extension_urls::kChromeWebstoreBaseURL); + return base_url_; +} + +// Returns the URL to use for update manifest queries. +const GURL &ExtensionsClientQt::GetWebstoreUpdateURL() const +{ + if (update_url_.is_empty()) + update_url_ = GURL(extension_urls::GetWebstoreUpdateUrl()); + return update_url_; +} + +// Returns a flag indicating whether or not a given URL is a valid +// extension blacklist URL. +bool ExtensionsClientQt::IsBlacklistUpdateURL(const GURL &url) const +{ + return true; +} + +// Returns the set of file paths corresponding to any images within an +// extension's contents that may be displayed directly within the browser UI +// or WebUI, such as icons or theme images. This set of paths is used by the +// extension unpacker to determine which assets should be transcoded safely +// within the utility sandbox. +// +// The default implementation returns the images used as icons for the +// extension itself, so implementors of ExtensionsClient overriding this may +// want to call the base class version and then add additional paths to that +// result. +std::set<base::FilePath> ExtensionsClientQt::GetBrowserImagePaths(const Extension *extension) +{ + return ExtensionsClient::GetBrowserImagePaths(extension); +} + +} // namespace extensions diff --git a/src/core/common/extensions/extensions_client_qt.h b/src/core/common/extensions/extensions_client_qt.h new file mode 100644 index 000000000..657487277 --- /dev/null +++ b/src/core/common/extensions/extensions_client_qt.h @@ -0,0 +1,148 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// Portions copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef EXTENSIONS_CLIENT_QT_H +#define EXTENSIONS_CLIENT_QT_H + +#include "extensions/common/extensions_client.h" + +#include "base/compiler_specific.h" +#include "base/lazy_instance.h" +#include "base/macros.h" +#include "chrome/common/extensions/permissions/chrome_permission_message_provider.h" +#include "extensions/common/features/feature_provider.h" +#include "extensions/common/features/json_feature_provider_source.h" +#include "extensions/common/permissions/extensions_api_permissions.h" +#include "url/gurl.h" + +namespace extensions { + +// Sets up global state for the extensions system. Should be Set() once in each +// process. This should be implemented by the client of the extensions system. +class ExtensionsClientQt : public ExtensionsClient +{ +public: + ExtensionsClientQt(); + virtual ~ExtensionsClientQt() {} + + // Initializes global state. Not done in the constructor because unit tests + // can create additional ExtensionsClients because the utility thread runs + // in-process. + void Initialize() override; + void InitializeWebStoreUrls(base::CommandLine *command_line) override; + + // Returns the global PermissionMessageProvider to use to provide permission + // warning strings. + const PermissionMessageProvider &GetPermissionMessageProvider() const override; + + // Returns the application name. For example, "Chromium" or "app_shell". + const std::string GetProductName() override; + + // Takes the list of all hosts and filters out those with special + // permission strings. Adds the regular hosts to |new_hosts|, + // and adds any additional permissions to |permissions|. + // TODO(sashab): Split this function in two: One to filter out ignored host + // permissions, and one to get permissions for the given hosts. + void FilterHostPermissions(const URLPatternSet &hosts, + URLPatternSet *new_hosts, + PermissionIDSet *permissions) const override; + + // Replaces the scripting whitelist with |whitelist|. Used in the renderer; + // only used for testing in the browser process. + void SetScriptingWhitelist(const ScriptingWhitelist &whitelist) override; + + // Return the whitelist of extensions that can run content scripts on + // any origin. + const ScriptingWhitelist &GetScriptingWhitelist() const override; + + // Get the set of chrome:// hosts that |extension| can run content scripts on. + URLPatternSet GetPermittedChromeSchemeHosts(const Extension *extension, + const APIPermissionSet &api_permissions) const override; + + // Returns false if content scripts are forbidden from running on |url|. + bool IsScriptableURL(const GURL &url, std::string *error) const override; + + // Determines if certain fatal extensions errors should be surpressed + // (i.e., only logged) or allowed (i.e., logged before crashing). + bool ShouldSuppressFatalErrors() const override; + + // Records that a fatal error was caught and suppressed. It is expected that + // embedders will only do so if ShouldSuppressFatalErrors at some point + // returned true. + void RecordDidSuppressFatalError() override; + + // Returns the base webstore URL prefix. + const GURL &GetWebstoreBaseURL() const override; + + // Returns the URL to use for update manifest queries. + const GURL &GetWebstoreUpdateURL() const override; + + // Returns a flag indicating whether or not a given URL is a valid + // extension blacklist URL. + bool IsBlacklistUpdateURL(const GURL &url) const override; + + // Returns the set of file paths corresponding to any images within an + // extension's contents that may be displayed directly within the browser UI + // or WebUI, such as icons or theme images. This set of paths is used by the + // extension unpacker to determine which assets should be transcoded safely + // within the utility sandbox. + // + // The default implementation returns the images used as icons for the + // extension itself, so implementors of ExtensionsClient overriding this may + // want to call the base class version and then add additional paths to that + // result. + std::set<base::FilePath> GetBrowserImagePaths(const Extension *extension) override; + // Get the LazyInstance for ChromeExtensionsClient. + static ExtensionsClientQt *GetInstance(); + +private: + ScriptingWhitelist scripting_whitelist_; + const ChromePermissionMessageProvider permission_message_provider_; + mutable GURL update_url_; + mutable GURL base_url_; + DISALLOW_COPY_AND_ASSIGN(ExtensionsClientQt); +}; + +} // namespace extensions + +#endif // EXTENSIONS_CLIENT_QT_H diff --git a/src/core/common/qt_messages.cpp b/src/core/common/qt_messages.cpp index d64db69c9..2f087d21f 100644 --- a/src/core/common/qt_messages.cpp +++ b/src/core/common/qt_messages.cpp @@ -10,10 +10,6 @@ #include "ipc/struct_constructor_macros.h" #include "common/qt_messages.h" -// Generate destructors. -#include "ipc/struct_destructor_macros.h" -#include "common/qt_messages.h" - // Generate param traits write methods. #include "ipc/param_traits_write_macros.h" namespace IPC { diff --git a/src/core/common/qt_messages.h b/src/core/common/qt_messages.h index 88c29f13b..9add826ae 100644 --- a/src/core/common/qt_messages.h +++ b/src/core/common/qt_messages.h @@ -111,9 +111,8 @@ IPC_MESSAGE_CONTROL4(QtWebEngineHostMsg_RequestFileSystemAccessAsync, // Sent by the renderer process to check whether access to Indexed DB is // granted by content settings. -IPC_SYNC_MESSAGE_CONTROL4_1(QtWebEngineHostMsg_AllowIndexedDB, +IPC_SYNC_MESSAGE_CONTROL3_1(QtWebEngineHostMsg_AllowIndexedDB, int /* render_frame_id */, GURL /* origin_url */, GURL /* top origin url */, - base::string16 /* database name */, bool /* allowed */) diff --git a/src/core/chromium_gpu_helper.cpp b/src/core/compositor/chromium_gpu_helper.cpp index 92a8b13ed..71d0f3687 100644 --- a/src/core/chromium_gpu_helper.cpp +++ b/src/core/compositor/chromium_gpu_helper.cpp @@ -43,10 +43,14 @@ #include "chromium_gpu_helper.h" +// Some headers include the namespace ws, and can not coexist with +// Qt headers that include QTextStream, which includes most QSG headers +// via QMatrix4x4. +#include "content/browser/renderer_host/render_widget_host_impl.h" + // Including gpu/command_buffer headers before content/gpu headers makes sure that // guards are defined to prevent duplicate definition errors with forward declared // GL typedefs cascading through content header includes. -#include "gpu/command_buffer/service/sync_point_manager.h" #include "gpu/command_buffer/service/mailbox_manager.h" #include "gpu/command_buffer/service/texture_base.h" @@ -62,12 +66,6 @@ scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner() return content::GpuChildThread::instance()->main_thread_runner(); } -gpu::SyncPointManager *sync_point_manager() -{ - gpu::GpuChannelManager *gpuChannelManager = content::GpuChildThread::instance()->gpu_channel_manager(); - return gpuChannelManager->sync_point_manager(); -} - gpu::MailboxManager *mailbox_manager() { gpu::GpuChannelManager *gpuChannelManager = content::GpuChildThread::instance()->gpu_channel_manager(); @@ -85,6 +83,11 @@ unsigned int service_id(gpu::TextureBase *tex) return tex->service_id(); } +void ProgressFlingIfNeeded(content::RenderWidgetHost *host, const base::TimeTicks ¤t_time) +{ + content::RenderWidgetHostImpl::From(host)->ProgressFlingIfNeeded(current_time); +} + #ifdef Q_OS_QNX EGLStreamData eglstream_connect_consumer(gpu::Texture *tex) { diff --git a/src/core/chromium_gpu_helper.h b/src/core/compositor/chromium_gpu_helper.h index 21b764997..4086d12ab 100644 --- a/src/core/chromium_gpu_helper.h +++ b/src/core/compositor/chromium_gpu_helper.h @@ -46,11 +46,15 @@ namespace base { class SingleThreadTaskRunner; +class TimeTicks; +} + +namespace content { +class RenderWidgetHost; } namespace gpu { struct Mailbox; -class SyncPointManager; class MailboxManager; class TextureBase; } @@ -61,12 +65,13 @@ class TextureBase; // functions should only be forward-declared and considered as opaque types. scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner(); -gpu::SyncPointManager *sync_point_manager(); gpu::MailboxManager *mailbox_manager(); gpu::TextureBase* ConsumeTexture(gpu::MailboxManager *mailboxManager, unsigned target, const gpu::Mailbox& mailbox); unsigned int service_id(gpu::TextureBase *tex); +void ProgressFlingIfNeeded(content::RenderWidgetHost *host, const base::TimeTicks ¤t_time); + #ifdef Q_OS_QNX typedef void* EGLDisplay; typedef void* EGLStreamKHR; diff --git a/src/core/compositor.cpp b/src/core/compositor/compositor.cpp index f7a5e651c..56693961c 100644 --- a/src/core/compositor.cpp +++ b/src/core/compositor/compositor.cpp @@ -39,26 +39,27 @@ #include "compositor.h" +#include "compositor_resource_tracker.h" #include "delegated_frame_node.h" -#include "render_widget_host_view_qt.h" +#include "base/task/post_task.h" #include "components/viz/common/resources/returned_resource.h" +#include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "services/viz/public/interfaces/compositing/compositor_frame_sink.mojom.h" namespace QtWebEngineCore { -Compositor::Compositor(RenderWidgetHostViewQt *hostView) - : m_chromiumCompositorData(new ChromiumCompositorData) - , m_view(hostView) +Compositor::Compositor(content::RenderWidgetHost *host) + : m_resourceTracker(new CompositorResourceTracker) + , m_host(host) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - base::SingleThreadTaskRunner *taskRunner = - content::BrowserThread::GetTaskRunnerForThread(content::BrowserThread::UI).get(); + m_taskRunner = base::CreateSingleThreadTaskRunnerWithTraits({content::BrowserThread::UI, base::TaskPriority::USER_VISIBLE}); m_beginFrameSource = std::make_unique<viz::DelayBasedBeginFrameSource>( - std::make_unique<viz::DelayBasedTimeSource>(taskRunner), + std::make_unique<viz::DelayBasedTimeSource>(m_taskRunner.get()), viz::BeginFrameSource::kNotRestartableId); } @@ -67,13 +68,6 @@ Compositor::~Compositor() DCHECK_CURRENTLY_ON(content::BrowserThread::UI); } -void Compositor::setViewDelegate(RenderWidgetHostViewQtDelegate *viewDelegate) -{ - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - - m_viewDelegate = viewDelegate; -} - void Compositor::setFrameSinkClient(viz::mojom::CompositorFrameSinkClient *frameSinkClient) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); @@ -85,7 +79,7 @@ void Compositor::setFrameSinkClient(viz::mojom::CompositorFrameSinkClient *frame // should not be returned. // // TODO(juvaldma): Can there be a pending frame from the old client? - m_resourcesToRelease.clear(); + m_resourceTracker->returnResources(); m_frameSinkClient = frameSinkClient; } @@ -104,21 +98,19 @@ void Compositor::setNeedsBeginFrames(bool needsBeginFrames) m_needsBeginFrames = needsBeginFrames; } -void Compositor::submitFrame(viz::CompositorFrame frame) +void Compositor::submitFrame(viz::CompositorFrame frame, base::OnceClosure callback) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - DCHECK(!m_havePendingFrame); + DCHECK(!m_submitCallback); - m_chromiumCompositorData->frameDevicePixelRatio = frame.metadata.device_scale_factor; - m_chromiumCompositorData->previousFrameData = std::move(m_chromiumCompositorData->frameData); - m_chromiumCompositorData->frameData = std::move(frame); - m_havePendingFrame = true; - - // Tell viewDelegate to call updatePaintNode() soon. - m_viewDelegate->update(); + m_pendingFrame = std::move(frame); + m_submitCallback = std::move(callback); + m_resourceTracker->submitResources( + m_pendingFrame, + base::BindOnce(&Compositor::runSubmitCallback, base::Unretained(this))); } -QSGNode *Compositor::updatePaintNode(QSGNode *oldNode) +QSGNode *Compositor::updatePaintNode(QSGNode *oldNode, RenderWidgetHostViewQtDelegate *viewDelegate) { // DCHECK_CURRENTLY_ON(content::BrowserThread::UI); // @@ -129,46 +121,59 @@ QSGNode *Compositor::updatePaintNode(QSGNode *oldNode) if (!frameNode) frameNode = new DelegatedFrameNode; - frameNode->commit(m_chromiumCompositorData.data(), &m_resourcesToRelease, m_viewDelegate); - - if (m_havePendingFrame) { - m_havePendingFrame = false; - content::BrowserThread::PostTask( - content::BrowserThread::UI, FROM_HERE, - base::BindOnce(&Compositor::notifyFrameCommitted, m_weakPtrFactory.GetWeakPtr())); + if (!m_updatePaintNodeShouldCommit) { + frameNode->commit(m_committedFrame, viz::CompositorFrame(), m_resourceTracker.get(), viewDelegate); + return frameNode; } - if (m_chromiumCompositorData->frameData.metadata.request_presentation_feedback) - content::BrowserThread::PostTask( - content::BrowserThread::UI, FROM_HERE, - base::BindOnce(&Compositor::sendPresentationFeedback, m_weakPtrFactory.GetWeakPtr(), m_chromiumCompositorData->frameData.metadata.frame_token)); + m_updatePaintNodeShouldCommit = false; + + gfx::PresentationFeedback dummyFeedback(base::TimeTicks::Now(), base::TimeDelta(), gfx::PresentationFeedback::Flags::kVSync); + m_presentations.insert({m_committedFrame.metadata.frame_token, dummyFeedback}); + + m_resourceTracker->commitResources(); + frameNode->commit(m_pendingFrame, m_committedFrame, m_resourceTracker.get(), viewDelegate); + m_committedFrame = std::move(m_pendingFrame); + m_pendingFrame = viz::CompositorFrame(); + + m_taskRunner->PostTask(FROM_HERE, + base::BindOnce(&Compositor::notifyFrameCommitted, m_weakPtrFactory.GetWeakPtr())); return frameNode; } +void Compositor::runSubmitCallback() +{ + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + + m_updatePaintNodeShouldCommit = true; + std::move(m_submitCallback).Run(); +} + void Compositor::notifyFrameCommitted() { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); m_beginFrameSource->DidFinishFrame(this); if (m_frameSinkClient) - m_frameSinkClient->DidReceiveCompositorFrameAck(m_resourcesToRelease); - m_resourcesToRelease.clear(); + m_frameSinkClient->DidReceiveCompositorFrameAck(m_resourceTracker->returnResources()); } void Compositor::sendPresentationFeedback(uint frame_token) { gfx::PresentationFeedback dummyFeedback(base::TimeTicks::Now(), base::TimeDelta(), gfx::PresentationFeedback::Flags::kVSync); - m_frameSinkClient->DidPresentCompositorFrame(frame_token, dummyFeedback); + m_presentations.insert({frame_token, dummyFeedback}); } bool Compositor::OnBeginFrameDerivedImpl(const viz::BeginFrameArgs &args) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - m_view->OnBeginFrame(args.frame_time); + ProgressFlingIfNeeded(m_host, args.frame_time); m_beginFrameSource->OnUpdateVSyncParameters(args.frame_time, args.interval); - if (m_frameSinkClient) - m_frameSinkClient->OnBeginFrame(args); + if (m_frameSinkClient) { + m_frameSinkClient->OnBeginFrame(args, m_presentations); + m_presentations.clear(); + } return true; } diff --git a/src/core/compositor.h b/src/core/compositor/compositor.h index 7d7db5d04..6d88dc054 100644 --- a/src/core/compositor.h +++ b/src/core/compositor/compositor.h @@ -40,8 +40,13 @@ #ifndef COMPOSITOR_H #define COMPOSITOR_H -#include <base/memory/weak_ptr.h> -#include <components/viz/common/frame_sinks/begin_frame_source.h> +#include "base/memory/weak_ptr.h" +#include "components/viz/common/frame_sinks/begin_frame_source.h" +#include "components/viz/common/quads/compositor_frame.h" +#include "ui/gfx/presentation_feedback.h" + +#include <QtCore/qglobal.h> +#include <QtCore/qshareddata.h> #include <QtCore/qglobal.h> #include <QtCore/qshareddata.h> @@ -50,8 +55,10 @@ QT_BEGIN_NAMESPACE class QSGNode; QT_END_NAMESPACE +namespace content { +class RenderWidgetHost; +} namespace viz { -class CompositorFrame; struct ReturnedResource; namespace mojom { class CompositorFrameSinkClient; @@ -60,9 +67,8 @@ class CompositorFrameSinkClient; namespace QtWebEngineCore { -class RenderWidgetHostViewQt; +class CompositorResourceTracker; class RenderWidgetHostViewQtDelegate; -class ChromiumCompositorData; // Receives viz::CompositorFrames from child compositors and provides QSGNodes // to the Qt Quick renderer. @@ -72,10 +78,10 @@ class ChromiumCompositorData; // Step 1. A new CompositorFrame is received from child compositors and handed // off to submitFrame(). The new frame will start off in a pending state. // -// Step 2. Once the new frame is ready to be rendered, Compositor will call -// update() on the delegate. +// Step 2. Once the new frame is ready to be rendered, Compositor will notify +// the client by running the callback given to submitFrame(). // -// Step 3. Once the delegate is ready to render, updatePaintNode() should be +// Step 3. Once the client is ready to render, updatePaintNode() should be // called to receive the scene graph for the new frame. This call will commit // the pending frame. Until the next frame is ready, all subsequent calls to // updatePaintNode() will keep using this same committed frame. @@ -85,18 +91,17 @@ class ChromiumCompositorData; class Compositor final : private viz::BeginFrameObserverBase { public: - explicit Compositor(RenderWidgetHostViewQt *hostView); + explicit Compositor(content::RenderWidgetHost *host); ~Compositor() override; - void setViewDelegate(RenderWidgetHostViewQtDelegate *viewDelegate); void setFrameSinkClient(viz::mojom::CompositorFrameSinkClient *frameSinkClient); void setNeedsBeginFrames(bool needsBeginFrames); - void submitFrame(viz::CompositorFrame frame); - - QSGNode *updatePaintNode(QSGNode *oldNode); + void submitFrame(viz::CompositorFrame frame, base::OnceClosure callback); + QSGNode *updatePaintNode(QSGNode *oldNode, RenderWidgetHostViewQtDelegate *viewDelegate); private: + void runSubmitCallback(); void notifyFrameCommitted(); void sendPresentationFeedback(uint frame_token); @@ -104,15 +109,18 @@ private: bool OnBeginFrameDerivedImpl(const viz::BeginFrameArgs &args) override; void OnBeginFrameSourcePausedChanged(bool paused) override; - std::vector<viz::ReturnedResource> m_resourcesToRelease; - QExplicitlySharedDataPointer<ChromiumCompositorData> m_chromiumCompositorData; - RenderWidgetHostViewQt *m_view; - RenderWidgetHostViewQtDelegate *m_viewDelegate = nullptr; + viz::CompositorFrame m_committedFrame; + viz::CompositorFrame m_pendingFrame; + base::OnceClosure m_submitCallback; + std::unique_ptr<CompositorResourceTracker> m_resourceTracker; + content::RenderWidgetHost *m_host; std::unique_ptr<viz::SyntheticBeginFrameSource> m_beginFrameSource; + base::flat_map<uint32_t, gfx::PresentationFeedback> m_presentations; viz::mojom::CompositorFrameSinkClient *m_frameSinkClient = nullptr; - bool m_havePendingFrame = false; + bool m_updatePaintNodeShouldCommit = false; bool m_needsBeginFrames = false; + scoped_refptr<base::SingleThreadTaskRunner> m_taskRunner; base::WeakPtrFactory<Compositor> m_weakPtrFactory{this}; DISALLOW_COPY_AND_ASSIGN(Compositor); diff --git a/src/core/compositor/compositor_resource.h b/src/core/compositor/compositor_resource.h new file mode 100644 index 000000000..f7df2ab59 --- /dev/null +++ b/src/core/compositor/compositor_resource.h @@ -0,0 +1,123 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef COMPOSITOR_RESOURCE_H +#define COMPOSITOR_RESOURCE_H + +#include <base/memory/ref_counted.h> +#include <components/viz/common/resources/transferable_resource.h> + +#include <QtCore/qglobal.h> +#include <QtGui/qtgui-config.h> + +#if QT_CONFIG(opengl) +# include "compositor_resource_fence.h" +#endif + +namespace viz { +class SharedBitmap; +} // namespace viz + +namespace QtWebEngineCore { + +using CompositorResourceId = quint32; + +// A resource (OpenGL texture or software shared bitmap). +// +// - Created by the CompositorResourceTracker from a newly submitted +// CompositorFrame's resource_list. +// +// - Until the frame is committed, its resources are in a 'pending' state and +// are inaccessible from outside the CompositorResourceTracker. +// +// - Once the frame is committed, its resources can be found via +// CompositorResourceTracker::findResource. +// +// - A committed resource's fields may not be updated and are safe to use from +// other threads without synchronization (unless noted otherwise). +class CompositorResource : public viz::TransferableResource +{ +public: + CompositorResource(const viz::TransferableResource &tr) : viz::TransferableResource(tr) {} + + // Counts the number of times this resource has been encountered in + // CompositorFrames' resource lists. + // + // Corresponds to viz::ReturnedResource::count. + // + // Updated by CompositorResourceTracker on UI thread. + int import_count = 1; + + // Identifies the last frame that needed this resource. Used by + // CompositorResourceTracker to return unused resources back to child + // compositors. + // + // Updated by CompositorResourceTracker on UI thread. + quint32 last_used_for_frame = 0; + + // Bitmap (if is_software). + std::unique_ptr<viz::SharedBitmap> bitmap; + +#if QT_CONFIG(opengl) + // OpenGL texture id (if !is_software). + quint32 texture_id = 0; + + // Should be waited on before using the texture (non-null if !is_software). + scoped_refptr<CompositorResourceFence> texture_fence; +#endif // QT_CONFIG(opengl) +}; + +inline bool operator<(const CompositorResource &r1, const CompositorResource &r2) +{ + return r1.id < r2.id; +} + +inline bool operator<(const CompositorResource &r, CompositorResourceId id) +{ + return r.id < id; +} + +inline bool operator<(CompositorResourceId id, const CompositorResource &r) +{ + return id < r.id; +} + +} // namespace QtWebEngineCore + +#endif // !COMPOSITOR_RESOURCE_H diff --git a/src/core/compositor/compositor_resource_fence.cpp b/src/core/compositor/compositor_resource_fence.cpp new file mode 100644 index 000000000..7fc5fbfb2 --- /dev/null +++ b/src/core/compositor/compositor_resource_fence.cpp @@ -0,0 +1,158 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "compositor_resource_fence.h" + +#include "ui/gl/gl_context.h" + +#include <QtGui/qopenglcontext.h> + +#ifndef GL_TIMEOUT_IGNORED +#define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFFull +#endif + +namespace QtWebEngineCore { + +void CompositorResourceFence::wait() +{ + if (!m_sync) + return; + + QOpenGLContext *context = QOpenGLContext::currentContext(); + Q_ASSERT(context); + + // Chromium uses its own GL bindings and stores in in thread local storage. + // For that reason, let chromium_gpu_helper.cpp contain the producing code that will run in the Chromium + // GPU thread, and put the sync consuming code here that will run in the QtQuick SG or GUI thread. + switch (m_sync.type) { + case gl::TransferableFence::NoSync: + break; + case gl::TransferableFence::EglSync: +#ifdef EGL_KHR_reusable_sync + { + static bool resolved = false; + static PFNEGLCLIENTWAITSYNCKHRPROC eglClientWaitSyncKHR = 0; + + if (!resolved) { + if (gl::GLSurfaceQt::HasEGLExtension("EGL_KHR_fence_sync")) + eglClientWaitSyncKHR = (PFNEGLCLIENTWAITSYNCKHRPROC)context->getProcAddress("eglClientWaitSyncKHR"); + resolved = true; + } + + if (eglClientWaitSyncKHR) + // FIXME: Use the less wasteful eglWaitSyncKHR once we have a device that supports EGL_KHR_wait_sync. + eglClientWaitSyncKHR(m_sync.egl.display, m_sync.egl.sync, 0, EGL_FOREVER_KHR); + } +#endif + break; + case gl::TransferableFence::ArbSync: + typedef void (QOPENGLF_APIENTRYP WaitSyncPtr)(GLsync sync, GLbitfield flags, GLuint64 timeout); + static WaitSyncPtr glWaitSync_ = 0; + if (!glWaitSync_) { + glWaitSync_ = (WaitSyncPtr)context->getProcAddress("glWaitSync"); + Q_ASSERT(glWaitSync_); + } + glWaitSync_(m_sync.arb.sync, 0, GL_TIMEOUT_IGNORED); + break; + } + + release(); +} + +void CompositorResourceFence::release() +{ + if (!m_sync) + return; + + QOpenGLContext *context = QOpenGLContext::currentContext(); + if (!context) + return; + + // Chromium uses its own GL bindings and stores in in thread local storage. + // For that reason, let chromium_gpu_helper.cpp contain the producing code that will run in the Chromium + // GPU thread, and put the sync consuming code here that will run in the QtQuick SG or GUI thread. + switch (m_sync.type) { + case gl::TransferableFence::NoSync: + break; + case gl::TransferableFence::EglSync: +#ifdef EGL_KHR_reusable_sync + { + static bool resolved = false; + static PFNEGLDESTROYSYNCKHRPROC eglDestroySyncKHR = 0; + + if (!resolved) { + if (gl::GLSurfaceQt::HasEGLExtension("EGL_KHR_fence_sync")) + eglDestroySyncKHR = (PFNEGLDESTROYSYNCKHRPROC)context->getProcAddress("eglDestroySyncKHR"); + resolved = true; + } + + if (eglDestroySyncKHR) { + // FIXME: Use the less wasteful eglWaitSyncKHR once we have a device that supports EGL_KHR_wait_sync. + eglDestroySyncKHR(m_sync.egl.display, m_sync.egl.sync); + m_sync.reset(); + } + } +#endif + break; + case gl::TransferableFence::ArbSync: + typedef void (QOPENGLF_APIENTRYP DeleteSyncPtr)(GLsync sync); + static DeleteSyncPtr glDeleteSync_ = 0; + if (!glDeleteSync_) { + glDeleteSync_ = (DeleteSyncPtr)context->getProcAddress("glDeleteSync"); + Q_ASSERT(glDeleteSync_); + } + glDeleteSync_(m_sync.arb.sync); + m_sync.reset(); + break; + } + // If Chromium was able to create a sync, we should have been able to handle its type here too. + Q_ASSERT(!m_sync); +} + +// static +scoped_refptr<CompositorResourceFence> CompositorResourceFence::create() +{ + if (gl::GLContext::GetCurrent() && gl::GLFence::IsSupported()) { + std::unique_ptr<gl::GLFence> glFence{gl::GLFence::Create()}; + return base::MakeRefCounted<CompositorResourceFence>(glFence->Transfer()); + } + return nullptr; +} + +} // namespace QtWebEngineCore diff --git a/src/core/compositor/compositor_resource_fence.h b/src/core/compositor/compositor_resource_fence.h new file mode 100644 index 000000000..1c2ea3695 --- /dev/null +++ b/src/core/compositor/compositor_resource_fence.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef COMPOSITOR_RESOURCE_FENCE_H +#define COMPOSITOR_RESOURCE_FENCE_H + +#include <base/memory/ref_counted.h> +#include <ui/gl/gl_fence.h> + +namespace QtWebEngineCore { + +// Sync object created on GPU thread and consumed on render thread. +class CompositorResourceFence final : public base::RefCountedThreadSafe<CompositorResourceFence> +{ +public: + REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE(); + + CompositorResourceFence() {} + CompositorResourceFence(const gl::TransferableFence &sync) : m_sync(sync) {}; + ~CompositorResourceFence() { release(); } + + // May be used only by Qt Quick render thread. + void wait(); + void release(); + + // May be used only by GPU thread. + static scoped_refptr<CompositorResourceFence> create(); + +private: + gl::TransferableFence m_sync; +}; + +} // namespace QtWebEngineCore + +#endif // !COMPOSITOR_RESOURCE_FENCE_H diff --git a/src/core/compositor/compositor_resource_tracker.cpp b/src/core/compositor/compositor_resource_tracker.cpp new file mode 100644 index 000000000..741c2717c --- /dev/null +++ b/src/core/compositor/compositor_resource_tracker.cpp @@ -0,0 +1,266 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "compositor_resource_tracker.h" + +#include "chromium_gpu_helper.h" +#include "render_widget_host_view_qt_delegate.h" +#include "web_engine_context.h" + +#include "base/message_loop/message_loop.h" +#include "base/task/post_task.h" +#include "components/viz/common/quads/compositor_frame.h" +#include "components/viz/common/resources/returned_resource.h" +#include "components/viz/service/display_embedder/server_shared_bitmap_manager.h" +#include "content/browser/browser_main_loop.h" +#include "content/public/browser/browser_task_traits.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/gpu/content_gpu_client.h" +#include "gpu/command_buffer/service/mailbox_manager.h" +#include "gpu/command_buffer/service/sync_point_manager.h" + +namespace QtWebEngineCore { + +CompositorResourceTracker::CompositorResourceTracker() +{} + +CompositorResourceTracker::~CompositorResourceTracker() +{} + +void CompositorResourceTracker::submitResources(const viz::CompositorFrame &frame, base::OnceClosure callback) +{ + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + DCHECK(!m_submitCallback); + DCHECK(m_pendingResources.empty()); + DCHECK(m_pendingImports.empty()); + DCHECK(m_pendingResourceUpdates == 0); + + m_submitCallback = std::move(callback); + + m_pendingResources.reserve(frame.resource_list.size()); + m_pendingImports.reserve(frame.resource_list.size()); + + for (const viz::TransferableResource &transferableResource : frame.resource_list) { + auto it = m_committedResources.find(transferableResource.id); + if (it != m_committedResources.end()) + m_pendingImports.push_back(&*it); + else + m_pendingResources.emplace_back(transferableResource); + } + + if (m_pendingResources.empty()) { + scheduleRunSubmitCallback(); + return; + } + + m_pendingResourceUpdates = m_pendingResources.size(); + + std::vector<CompositorResource *> batch; + batch.reserve(m_pendingResources.size()); + + for (CompositorResource &resource : m_pendingResources) { + if (resource.is_software) + updateBitmap(&resource); + else if (!scheduleUpdateMailbox(&resource)) + batch.push_back(&resource); + } + + if (!batch.empty()) + scheduleUpdateMailboxes(std::move(batch)); +} + +void CompositorResourceTracker::commitResources() +{ + // DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + // + // This might be called from a Qt Quick render thread, but the UI thread + // will still be blocked for the duration of this call. + + DCHECK(m_pendingResourceUpdates == 0); + + for (CompositorResource *resource : m_pendingImports) + resource->import_count++; + m_pendingImports.clear(); + + m_committedResources.insert(std::make_move_iterator(m_pendingResources.begin()), + std::make_move_iterator(m_pendingResources.end())); + m_pendingResources.clear(); + + ++m_committedFrameId; +} + +std::vector<viz::ReturnedResource> CompositorResourceTracker::returnResources() +{ + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + + std::vector<viz::ReturnedResource> returnedResources; + base::EraseIf(m_committedResources, [&](const CompositorResource &resource) { + if (resource.last_used_for_frame != m_committedFrameId) { + viz::ReturnedResource returnedResource; + returnedResource.id = resource.id; + returnedResource.count = resource.import_count; + returnedResources.push_back(std::move(returnedResource)); + return true; + } + return false; + }); + return returnedResources; +} + +const CompositorResource *CompositorResourceTracker::findResource(CompositorResourceId id) const +{ + auto it = m_committedResources.find(id); + DCHECK(it != m_committedResources.end()); + + const_cast<CompositorResource &>(*it).last_used_for_frame = m_committedFrameId; + + return &*it; +} + +void CompositorResourceTracker::updateBitmap(CompositorResource *resource) +{ + content::BrowserMainLoop *browserMainLoop = content::BrowserMainLoop::GetInstance(); + viz::ServerSharedBitmapManager *bitmapManager = browserMainLoop->GetServerSharedBitmapManager(); + + resource->bitmap = bitmapManager->GetSharedBitmapFromId( + resource->size, + viz::BGRA_8888, + resource->mailbox_holder.mailbox); + + if (--m_pendingResourceUpdates == 0) + scheduleRunSubmitCallback(); +} + +quint32 CompositorResourceTracker::consumeMailbox(const gpu::MailboxHolder &mailboxHolder) +{ +#if QT_CONFIG(opengl) + gpu::MailboxManager *mailboxManager = mailbox_manager(); + DCHECK(mailboxManager); + if (mailboxHolder.sync_token.HasData()) + mailboxManager->PullTextureUpdates(mailboxHolder.sync_token); + gpu::TextureBase *tex = mailboxManager->ConsumeTexture(mailboxHolder.mailbox); + return tex ? service_id(tex) : 0; +#else + NOTREACHED(); +#endif // QT_CONFIG(OPENGL) +} + +bool CompositorResourceTracker::scheduleUpdateMailbox(CompositorResource *resource) +{ +#if QT_CONFIG(opengl) + gpu::SyncPointManager *syncPointManager = WebEngineContext::syncPointManager(); + DCHECK(syncPointManager); + return syncPointManager->WaitOutOfOrder( + resource->mailbox_holder.sync_token, + base::BindOnce(&CompositorResourceTracker::updateMailbox, + m_weakPtrFactory.GetWeakPtr(), + resource)); +#else + NOTREACHED(); +#endif // QT_CONFIG(OPENGL) +} + +void CompositorResourceTracker::updateMailbox(CompositorResource *resource) +{ +#if QT_CONFIG(opengl) + resource->texture_id = consumeMailbox(resource->mailbox_holder); + resource->texture_fence = CompositorResourceFence::create(); + + if (--m_pendingResourceUpdates == 0) + scheduleRunSubmitCallback(); +#else + NOTREACHED(); +#endif // QT_CONFIG(OPENGL) +} + +void CompositorResourceTracker::scheduleUpdateMailboxes(std::vector<CompositorResource *> resources) +{ +#if QT_CONFIG(opengl) + scoped_refptr<base::SingleThreadTaskRunner> gpuTaskRunner = gpu_task_runner(); + DCHECK(gpuTaskRunner); + thread_local bool currentThreadIsGpu = gpuTaskRunner->BelongsToCurrentThread(); + if (currentThreadIsGpu) + return updateMailboxes(std::move(resources)); + gpuTaskRunner->PostTask( + FROM_HERE, + base::BindOnce(&CompositorResourceTracker::updateMailboxes, + m_weakPtrFactory.GetWeakPtr(), + std::move(resources))); +#else + NOTREACHED(); +#endif // QT_CONFIG(OPENGL) +} + +void CompositorResourceTracker::updateMailboxes(std::vector<CompositorResource *> resources) +{ +#if QT_CONFIG(opengl) + for (CompositorResource *resource : resources) + resource->texture_id = consumeMailbox(resource->mailbox_holder); + + scoped_refptr<CompositorResourceFence> fence = CompositorResourceFence::create(); + + for (CompositorResource *resource : resources) + resource->texture_fence = fence; + + if ((m_pendingResourceUpdates -= resources.size()) == 0) + scheduleRunSubmitCallback(); +#else + NOTREACHED(); +#endif // QT_CONFIG(OPENGL) +} + +void CompositorResourceTracker::scheduleRunSubmitCallback() +{ + thread_local bool currentThreadIsUi = content::BrowserThread::CurrentlyOn(content::BrowserThread::UI); + if (currentThreadIsUi) + return runSubmitCallback(); + base::PostTaskWithTraits( + FROM_HERE, { content::BrowserThread::UI, base::TaskPriority::USER_VISIBLE }, + base::BindOnce(&CompositorResourceTracker::runSubmitCallback, + m_weakPtrFactory.GetWeakPtr())); +} + +void CompositorResourceTracker::runSubmitCallback() +{ + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + + std::move(m_submitCallback).Run(); +} + +} // namespace QtWebEngineCore diff --git a/src/core/compositor/compositor_resource_tracker.h b/src/core/compositor/compositor_resource_tracker.h new file mode 100644 index 000000000..887309395 --- /dev/null +++ b/src/core/compositor/compositor_resource_tracker.h @@ -0,0 +1,126 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef COMPOSITOR_RESOURCE_TRACKER_H +#define COMPOSITOR_RESOURCE_TRACKER_H + +#include "compositor_resource.h" +#include "locked_ptr.h" + +#include <base/callback.h> +#include <base/containers/flat_set.h> + +#include <atomic> +#include <vector> + +namespace viz { +class CompositorFrame; +struct ReturnedResource; +} // namespace viz + +namespace gpu { +struct MailboxHolder; +} // namespace gpu + +namespace QtWebEngineCore { + +// Ensures resources are not used before they are ready. +// +// The life cycle of a frame's resources: +// +// Step 1. A new CompositorFrame is received and given to submitResources(). +// The frame's resources will extracted and initialized to a pending state. +// +// Step 2. Once the new resources are ready to be committed, +// CompositorResourceTracker will notify the client by running the callback +// given to submitResources(). +// +// Step 3. Once the client is ready to render, commitResources() should be +// called. This will commit all the pending resources, making them available +// via findResource(). +// +// Step 4. Once all the resources have been used (via findResource()), +// returnResources() may be called to return a list of all the resources which +// were *not* used since the last commitResources(). Go to step 1. +class CompositorResourceTracker final +{ +public: + CompositorResourceTracker(); + ~CompositorResourceTracker(); + + void submitResources(const viz::CompositorFrame &frame, base::OnceClosure callback); + void commitResources(); + std::vector<viz::ReturnedResource> returnResources(); + + // The returned pointer is invalidated by the next call to commitFrame() or + // returnResources(). It should therefore not be stored in data structures + // but used immediately. + // + // Do not ask for resources which do not exist. + const CompositorResource *findResource(CompositorResourceId id) const; + +private: + void updateBitmap(CompositorResource *resource); + + quint32 consumeMailbox(const gpu::MailboxHolder &mailboxHolder); + + bool scheduleUpdateMailbox(CompositorResource *resource); + void updateMailbox(CompositorResource *resource); + + void scheduleUpdateMailboxes(std::vector<CompositorResource *> resources); + void updateMailboxes(std::vector<CompositorResource *> resources); + + void scheduleRunSubmitCallback(); + void runSubmitCallback(); + + base::flat_set<CompositorResource> m_committedResources; + std::vector<CompositorResource> m_pendingResources; + std::vector<CompositorResource *> m_pendingImports; + base::OnceClosure m_submitCallback; + std::atomic<size_t> m_pendingResourceUpdates{0}; + quint32 m_committedFrameId = 0; + + base::LockedPtrFactory<CompositorResourceTracker> m_weakPtrFactory{this}; + + DISALLOW_COPY_AND_ASSIGN(CompositorResourceTracker); +}; + +} // namespace QtWebEngineCore + +#endif // !COMPOSITOR_RESOURCE_TRACKER_H diff --git a/src/core/compositor/content_gpu_client_qt.cpp b/src/core/compositor/content_gpu_client_qt.cpp new file mode 100644 index 000000000..f934979a0 --- /dev/null +++ b/src/core/compositor/content_gpu_client_qt.cpp @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "content_gpu_client_qt.h" + +#include "web_engine_context.h" + +namespace QtWebEngineCore { + +ContentGpuClientQt::ContentGpuClientQt() +{ +} + +ContentGpuClientQt::~ContentGpuClientQt() +{ +} + +gpu::SyncPointManager *ContentGpuClientQt::GetSyncPointManager() +{ + return WebEngineContext::syncPointManager(); +} + +} // namespace diff --git a/src/core/compositor/content_gpu_client_qt.h b/src/core/compositor/content_gpu_client_qt.h new file mode 100644 index 000000000..d7ad43881 --- /dev/null +++ b/src/core/compositor/content_gpu_client_qt.h @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef CONTENT_GPU_CLIENT_QT_H +#define CONTENT_GPU_CLIENT_QT_H + +#include "content/public/gpu/content_gpu_client.h" + +namespace QtWebEngineCore { + +class ContentGpuClientQt : public content::ContentGpuClient { +public: + explicit ContentGpuClientQt(); + ~ContentGpuClientQt() override; + + // content::ContentGpuClient implementation. + gpu::SyncPointManager *GetSyncPointManager() override; +}; + +} + +#endif // CONTENT_GPU_CLIENT_QT_H diff --git a/src/core/delegated_frame_node.cpp b/src/core/compositor/delegated_frame_node.cpp index 8ac82dbf1..5f474cbfb 100644 --- a/src/core/delegated_frame_node.cpp +++ b/src/core/compositor/delegated_frame_node.cpp @@ -49,17 +49,14 @@ #include "delegated_frame_node.h" #include "chromium_gpu_helper.h" -#include "ozone/gl_surface_qt.h" #include "stream_video_node.h" #include "type_conversion.h" #include "yuv_video_node.h" +#include "compositor_resource_tracker.h" #include "base/bind.h" -#include "base/message_loop/message_loop.h" -#include "base/threading/thread_task_runner_handle.h" #include "cc/base/math_util.h" #include "components/viz/common/quads/compositor_frame.h" -#include "components/viz/common/quads/compositor_frame_metadata.h" #include "components/viz/common/quads/debug_border_draw_quad.h" #include "components/viz/common/quads/draw_quad.h" #include "components/viz/common/quads/render_pass_draw_quad.h" @@ -68,14 +65,8 @@ #include "components/viz/common/quads/texture_draw_quad.h" #include "components/viz/common/quads/tile_draw_quad.h" #include "components/viz/common/quads/yuv_video_draw_quad.h" -#include "components/viz/common/resources/returned_resource.h" -#include "components/viz/common/resources/transferable_resource.h" #include "components/viz/service/display/bsp_tree.h" #include "components/viz/service/display_embedder/server_shared_bitmap_manager.h" -#include "content/browser/browser_main_loop.h" -#include "gpu/command_buffer/service/mailbox_manager.h" -#include "ui/gl/gl_context.h" -#include "ui/gl/gl_fence.h" #ifndef QT_NO_OPENGL # include <QOpenGLContext> @@ -93,10 +84,6 @@ #include <EGL/eglext.h> #endif -#ifndef GL_TIMEOUT_IGNORED -#define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFFull -#endif - #ifndef GL_TEXTURE_RECTANGLE #define GL_TEXTURE_RECTANGLE 0x84F5 #endif @@ -131,7 +118,7 @@ namespace QtWebEngineCore { #ifndef QT_NO_OPENGL class MailboxTexture : public QSGTexture, protected QOpenGLFunctions { public: - MailboxTexture(const gpu::MailboxHolder &mailboxHolder, const QSize textureSize); + MailboxTexture(const CompositorResource *resource, bool hasAlphaChannel, int target = -1); ~MailboxTexture(); // QSGTexture: int textureId() const override { return m_textureId; } @@ -140,14 +127,9 @@ public: bool hasMipmaps() const override { return false; } void bind() override; - void setHasAlphaChannel(bool hasAlpha) { m_hasAlpha = hasAlpha; } - gpu::MailboxHolder &mailboxHolder() { return m_mailboxHolder; } - void fetchTexture(gpu::MailboxManager *mailboxManager); - void setTarget(GLenum target); - private: - gpu::MailboxHolder m_mailboxHolder; int m_textureId; + scoped_refptr<CompositorResourceFence> m_fence; QSize m_textureSize; bool m_hasAlpha; GLenum m_target; @@ -160,20 +142,6 @@ private: friend class DelegatedFrameNode; }; #endif // QT_NO_OPENGL -class ResourceHolder { -public: - ResourceHolder(const viz::TransferableResource &resource); - QSharedPointer<QSGTexture> initTexture(bool quadIsAllOpaque, RenderWidgetHostViewQtDelegate *apiDelegate = 0); - QSGTexture *texture() const { return m_texture.data(); } - viz::ReturnedResource returnResource(); - void incImportCount() { ++m_importCount; } - bool needsToFetch() const { return !m_resource.is_software && m_texture && !m_texture.data()->textureId(); } - -private: - QWeakPointer<QSGTexture> m_texture; - viz::TransferableResource m_resource; - int m_importCount; -}; class RectClipNode : public QSGClipNode { @@ -443,7 +411,9 @@ static QSGNode *buildLayerChain(QSGNode *chainParent, const viz::SharedQuadState } if (!layerState->quad_to_target_transform.IsIdentity()) { QSGTransformNode *transformNode = new QSGTransformNode; - transformNode->setMatrix(toQt(layerState->quad_to_target_transform.matrix())); + QMatrix4x4 qMatrix; + convertToQt(layerState->quad_to_target_transform.matrix(), qMatrix); + transformNode->setMatrix(qMatrix); layerChain->appendChildNode(transformNode); layerChain = transformNode; } @@ -457,99 +427,12 @@ static QSGNode *buildLayerChain(QSGNode *chainParent, const viz::SharedQuadState } #ifndef QT_NO_OPENGL -static void waitChromiumSync(gl::TransferableFence *sync) -{ - // Chromium uses its own GL bindings and stores in in thread local storage. - // For that reason, let chromium_gpu_helper.cpp contain the producing code that will run in the Chromium - // GPU thread, and put the sync consuming code here that will run in the QtQuick SG or GUI thread. - switch (sync->type) { - case gl::TransferableFence::NoSync: - break; - case gl::TransferableFence::EglSync: -#ifdef EGL_KHR_reusable_sync - { - static bool resolved = false; - static PFNEGLCLIENTWAITSYNCKHRPROC eglClientWaitSyncKHR = 0; - - if (!resolved) { - if (gl::GLSurfaceQt::HasEGLExtension("EGL_KHR_fence_sync")) { - QOpenGLContext *context = QOpenGLContext::currentContext(); - eglClientWaitSyncKHR = (PFNEGLCLIENTWAITSYNCKHRPROC)context->getProcAddress("eglClientWaitSyncKHR"); - } - resolved = true; - } - - if (eglClientWaitSyncKHR) - // FIXME: Use the less wasteful eglWaitSyncKHR once we have a device that supports EGL_KHR_wait_sync. - eglClientWaitSyncKHR(sync->egl.display, sync->egl.sync, 0, EGL_FOREVER_KHR); - } -#endif - break; - case gl::TransferableFence::ArbSync: - typedef void (QOPENGLF_APIENTRYP WaitSyncPtr)(GLsync sync, GLbitfield flags, GLuint64 timeout); - static WaitSyncPtr glWaitSync_ = 0; - if (!glWaitSync_) { - QOpenGLContext *context = QOpenGLContext::currentContext(); - glWaitSync_ = (WaitSyncPtr)context->getProcAddress("glWaitSync"); - Q_ASSERT(glWaitSync_); - } - glWaitSync_(sync->arb.sync, 0, GL_TIMEOUT_IGNORED); - break; - } -} - -static void deleteChromiumSync(gl::TransferableFence *sync) -{ - // Chromium uses its own GL bindings and stores in in thread local storage. - // For that reason, let chromium_gpu_helper.cpp contain the producing code that will run in the Chromium - // GPU thread, and put the sync consuming code here that will run in the QtQuick SG or GUI thread. - switch (sync->type) { - case gl::TransferableFence::NoSync: - break; - case gl::TransferableFence::EglSync: -#ifdef EGL_KHR_reusable_sync - { - static bool resolved = false; - static PFNEGLDESTROYSYNCKHRPROC eglDestroySyncKHR = 0; - - if (!resolved) { - if (gl::GLSurfaceQt::HasEGLExtension("EGL_KHR_fence_sync")) { - QOpenGLContext *context = QOpenGLContext::currentContext(); - eglDestroySyncKHR = (PFNEGLDESTROYSYNCKHRPROC)context->getProcAddress("eglDestroySyncKHR"); - } - resolved = true; - } - - if (eglDestroySyncKHR) { - // FIXME: Use the less wasteful eglWaitSyncKHR once we have a device that supports EGL_KHR_wait_sync. - eglDestroySyncKHR(sync->egl.display, sync->egl.sync); - sync->reset(); - } - } -#endif - break; - case gl::TransferableFence::ArbSync: - typedef void (QOPENGLF_APIENTRYP DeleteSyncPtr)(GLsync sync); - static DeleteSyncPtr glDeleteSync_ = 0; - if (!glDeleteSync_) { - QOpenGLContext *context = QOpenGLContext::currentContext(); - glDeleteSync_ = (DeleteSyncPtr)context->getProcAddress("glDeleteSync"); - Q_ASSERT(glDeleteSync_); - } - glDeleteSync_(sync->arb.sync); - sync->reset(); - break; - } - // If Chromium was able to create a sync, we should have been able to handle its type here too. - Q_ASSERT(!*sync); -} - -MailboxTexture::MailboxTexture(const gpu::MailboxHolder &mailboxHolder, const QSize textureSize) - : m_mailboxHolder(mailboxHolder) - , m_textureId(0) - , m_textureSize(textureSize) - , m_hasAlpha(false) - , m_target(GL_TEXTURE_2D) +MailboxTexture::MailboxTexture(const CompositorResource *resource, bool hasAlphaChannel, int target) + : m_textureId(resource->texture_id) + , m_fence(resource->texture_fence) + , m_textureSize(toQt(resource->size)) + , m_hasAlpha(hasAlphaChannel) + , m_target(target >= 0 ? target : GL_TEXTURE_2D) #if defined(USE_OZONE) , m_ownsTexture(false) #endif @@ -580,6 +463,8 @@ MailboxTexture::~MailboxTexture() void MailboxTexture::bind() { + if (m_fence) + m_fence->wait(); glBindTexture(m_target, m_textureId); #ifdef Q_OS_QNX if (m_target == GL_TEXTURE_EXTERNAL_OES) { @@ -596,96 +481,7 @@ void MailboxTexture::bind() } #endif } - -void MailboxTexture::setTarget(GLenum target) -{ - m_target = target; -} - -void MailboxTexture::fetchTexture(gpu::MailboxManager *mailboxManager) -{ - gpu::TextureBase *tex = ConsumeTexture(mailboxManager, m_target, m_mailboxHolder.mailbox); - - // The texture might already have been deleted (e.g. when navigating away from a page). - if (tex) { - m_textureId = service_id(tex); -#ifdef Q_OS_QNX - if (m_target == GL_TEXTURE_EXTERNAL_OES) { - m_eglStreamData = eglstream_connect_consumer(tex); - } -#endif - } -} -#endif //QT_NO_OPENGL - -ResourceHolder::ResourceHolder(const viz::TransferableResource &resource) - : m_resource(resource) - , m_importCount(1) -{ -} - -QSharedPointer<QSGTexture> ResourceHolder::initTexture(bool quadNeedsBlending, RenderWidgetHostViewQtDelegate *apiDelegate) -{ - QSharedPointer<QSGTexture> texture = m_texture.toStrongRef(); - if (!texture) { - if (m_resource.is_software) { - Q_ASSERT(apiDelegate); - std::unique_ptr<viz::SharedBitmap> sharedBitmap = - content::BrowserMainLoop::GetInstance()->GetServerSharedBitmapManager()->GetSharedBitmapFromId( - m_resource.size, viz::BGRA_8888, m_resource.mailbox_holder.mailbox); - // QSG interprets QImage::hasAlphaChannel meaning that a node should enable blending - // to draw it but Chromium keeps this information in the quads. - // The input format is currently always Format_ARGB32_Premultiplied, so assume that all - // alpha bytes are 0xff if quads aren't requesting blending and avoid the conversion - // from Format_ARGB32_Premultiplied to Format_RGB32 just to get hasAlphaChannel to - // return false. - QImage::Format format = quadNeedsBlending ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32; - QImage image = sharedBitmap - ? QImage(sharedBitmap->pixels(), m_resource.size.width(), m_resource.size.height(), format) - : QImage(m_resource.size.width(), m_resource.size.height(), format); - texture.reset(apiDelegate->createTextureFromImage(image.copy())); - } else { -#ifndef QT_NO_OPENGL - texture.reset(new MailboxTexture(m_resource.mailbox_holder, toQt(m_resource.size))); - static_cast<MailboxTexture *>(texture.data())->setHasAlphaChannel(quadNeedsBlending); -#else - Q_UNREACHABLE(); -#endif - } - if (m_resource.filter == GL_NEAREST) - texture->setFiltering(QSGTexture::Nearest); - else if (m_resource.filter == GL_LINEAR) - texture->setFiltering(QSGTexture::Linear); - else { - // Depends on qtdeclarative fix, see QTBUG-71322 -#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 1) - texture->setFiltering(QSGTexture::Linear); -#else - texture->setFiltering(QSGTexture::Nearest); -#endif - } - m_texture = texture; - } - // All quads using a resource should request the same blending state. - Q_ASSERT(texture->hasAlphaChannel() || !quadNeedsBlending); - return texture; -} - -viz::ReturnedResource ResourceHolder::returnResource() -{ - viz::ReturnedResource returned; - // The ResourceProvider ensures that the resource isn't used by the parent compositor's GL - // context in the GPU process by inserting a sync point to be waited for by the child - // compositor's GL context. We don't need this since we are triggering the delegated frame - // ack directly from our rendering thread. At this point (in updatePaintNode) we know that - // a frame that was compositing any of those resources has already been swapped and we thus - // don't need to use this mechanism. - returned.id = m_resource.id; - returned.count = m_importCount; - m_importCount = 0; - return returned; -} - +#endif // !QT_NO_OPENGL RectClipNode::RectClipNode(const QRectF &rect) : m_geometry(QSGGeometry::defaultAttributes_Point2D(), 4) @@ -697,9 +493,8 @@ RectClipNode::RectClipNode(const QRectF &rect) } DelegatedFrameNode::DelegatedFrameNode() - : m_numPendingSyncPoints(0) #if defined(USE_OZONE) && !defined(QT_NO_OPENGL) - , m_contextShared(true) + : m_contextShared(true) #endif { setFlag(UsePreprocess); @@ -725,22 +520,6 @@ DelegatedFrameNode::~DelegatedFrameNode() void DelegatedFrameNode::preprocess() { -#ifndef QT_NO_OPENGL - // With the threaded render loop the GUI thread has been unlocked at this point. - // We can now wait for the Chromium GPU thread to produce textures that will be - // rendered on our quads and fetch the IDs from the mailboxes we were given. - QList<MailboxTexture *> mailboxesToFetch; - typedef QHash<unsigned, QSharedPointer<ResourceHolder> >::const_iterator ResourceHolderIterator; - ResourceHolderIterator end = m_chromiumCompositorData->resourceHolders.constEnd(); - for (ResourceHolderIterator it = m_chromiumCompositorData->resourceHolders.constBegin(); it != end ; ++it) { - if ((*it)->needsToFetch()) - mailboxesToFetch.append(static_cast<MailboxTexture *>((*it)->texture())); - } - - if (!mailboxesToFetch.isEmpty()) - fetchAndSyncMailboxes(mailboxesToFetch); -#endif - // Then render any intermediate RenderPass in order. typedef QPair<int, QSharedPointer<QSGLayer> > Pair; for (const Pair &pair : qAsConst(m_sgObjects.renderPassLayers)) { @@ -767,8 +546,8 @@ static bool areSharedQuadStatesEqual(const viz::SharedQuadState *layerState, // Compares if the frame data that we got from the Chromium Compositor is // *structurally* equivalent to the one of the previous frame. // If it is, we will just reuse and update the old nodes where necessary. -static bool areRenderPassStructuresEqual(viz::CompositorFrame *frameData, - viz::CompositorFrame *previousFrameData) +static bool areRenderPassStructuresEqual(const viz::CompositorFrame *frameData, + const viz::CompositorFrame *previousFrameData) { if (!previousFrameData) return false; @@ -820,12 +599,12 @@ static bool areRenderPassStructuresEqual(viz::CompositorFrame *frameData, return true; } -void DelegatedFrameNode::commit(ChromiumCompositorData *chromiumCompositorData, - std::vector<viz::ReturnedResource> *resourcesToRelease, +void DelegatedFrameNode::commit(const viz::CompositorFrame &pendingFrame, + const viz::CompositorFrame &committedFrame, + const CompositorResourceTracker *resourceTracker, RenderWidgetHostViewQtDelegate *apiDelegate) { - m_chromiumCompositorData = chromiumCompositorData; - viz::CompositorFrame* frameData = &m_chromiumCompositorData->frameData; + const viz::CompositorFrame* frameData = &pendingFrame; if (frameData->render_pass_list.empty()) return; @@ -833,30 +612,14 @@ void DelegatedFrameNode::commit(ChromiumCompositorData *chromiumCompositorData, // countering the scale of devicePixel-scaled tiles when rendering them // to the final surface. QMatrix4x4 matrix; - const float devicePixelRatio = m_chromiumCompositorData->frameDevicePixelRatio; + const float devicePixelRatio = frameData->metadata.device_scale_factor; matrix.scale(1 / devicePixelRatio, 1 / devicePixelRatio); if (QSGTransformNode::matrix() != matrix) setMatrix(matrix); - QHash<unsigned, QSharedPointer<ResourceHolder> > resourceCandidates; - qSwap(m_chromiumCompositorData->resourceHolders, resourceCandidates); - - // A frame's resource_list only contains the new resources to be added to the scene. Quads can - // still reference resources that were added in previous frames. Add them to the list of - // candidates to be picked up by quads, it's then our responsibility to return unused resources - // to the producing child compositor. - for (unsigned i = 0; i < frameData->resource_list.size(); ++i) { - const viz::TransferableResource &res = frameData->resource_list.at(i); - if (QSharedPointer<ResourceHolder> resource = resourceCandidates.value(res.id)) - resource->incImportCount(); - else - resourceCandidates[res.id] = QSharedPointer<ResourceHolder>(new ResourceHolder(res)); - } - - frameData->resource_list.clear(); QScopedPointer<DelegatedNodeTreeHandler> nodeHandler; - const QSizeF viewportSizeInPt = apiDelegate->screenRect().size(); + const QSizeF viewportSizeInPt = apiDelegate->viewGeometry().size(); const QSizeF viewportSizeF = viewportSizeInPt * devicePixelRatio; const QSize viewportSize(std::ceil(viewportSizeF.width()), std::ceil(viewportSizeF.height())); @@ -867,26 +630,22 @@ void DelegatedFrameNode::commit(ChromiumCompositorData *chromiumCompositorData, // Additionally, because we clip (i.e. don't build scene graph nodes for) quads outside // of the visible area, we also have to rebuild the tree whenever the window is resized. const bool buildNewTree = - !areRenderPassStructuresEqual(frameData, &m_chromiumCompositorData->previousFrameData) || + !areRenderPassStructuresEqual(frameData, &committedFrame) || m_sceneGraphNodes.empty() || viewportSize != m_previousViewportSize; - m_chromiumCompositorData->previousFrameData = viz::CompositorFrame(); - SGObjects previousSGObjects; - QVector<QSharedPointer<QSGTexture> > textureStrongRefs; if (buildNewTree) { // Keep the old objects in scope to hold a ref on layers, resources and textures // that we can re-use. Destroy the remaining objects before returning. - qSwap(m_sgObjects, previousSGObjects); + qSwap(m_sgObjects, m_previousSGObjects); // Discard the scene graph nodes from the previous frame. while (QSGNode *oldChain = firstChild()) delete oldChain; m_sceneGraphNodes.clear(); nodeHandler.reset(new DelegatedNodeTreeCreator(&m_sceneGraphNodes, apiDelegate)); } else { - // Save the texture strong refs so they only go out of scope when the method returns and - // the new vector of texture strong refs has been filled. - qSwap(m_sgObjects.textureStrongRefs, textureStrongRefs); + qSwap(m_sgObjects.bitmapTextures, m_previousSGObjects.bitmapTextures); + qSwap(m_sgObjects.mailboxTextures, m_previousSGObjects.mailboxTextures); nodeHandler.reset(new DelegatedNodeTreeUpdater(&m_sceneGraphNodes)); } // The RenderPasses list is actually a tree where a parent RenderPass is connected @@ -906,7 +665,7 @@ void DelegatedFrameNode::commit(ChromiumCompositorData *chromiumCompositorData, if (pass != rootRenderPass) { QSharedPointer<QSGLayer> rpLayer; if (buildNewTree) { - rpLayer = findRenderPassLayer(pass->id, previousSGObjects.renderPassLayers); + rpLayer = findRenderPassLayer(pass->id, m_previousSGObjects.renderPassLayers); if (!rpLayer) { rpLayer = QSharedPointer<QSGLayer>(apiDelegate->createLayer()); // Avoid any premature texture update since we need to wait @@ -935,7 +694,7 @@ void DelegatedFrameNode::commit(ChromiumCompositorData *chromiumCompositorData, } if (scissorRect.IsEmpty()) { - holdResources(pass, resourceCandidates); + holdResources(pass, resourceTracker); continue; } @@ -961,13 +720,13 @@ void DelegatedFrameNode::commit(ChromiumCompositorData *chromiumCompositorData, targetRect.Intersect(quadState->clip_rect); targetRect.Intersect(scissorRect); if (targetRect.IsEmpty()) { - holdResources(quad, resourceCandidates); + holdResources(quad, resourceTracker); continue; } if (quadState->sorting_context_id != currentSortingContextId) { flushPolygons(&polygonQueue, renderPassChain, - nodeHandler.data(), resourceCandidates, apiDelegate); + nodeHandler.data(), resourceTracker, apiDelegate); currentSortingContextId = quadState->sorting_context_id; } @@ -989,28 +748,23 @@ void DelegatedFrameNode::commit(ChromiumCompositorData *chromiumCompositorData, } handleQuad(quad, currentLayerChain, - nodeHandler.data(), resourceCandidates, apiDelegate); + nodeHandler.data(), resourceTracker, apiDelegate); } flushPolygons(&polygonQueue, renderPassChain, - nodeHandler.data(), resourceCandidates, apiDelegate); + nodeHandler.data(), resourceTracker, apiDelegate); } - // Send resources of remaining candidates back to the child compositors so that - // they can be freed or reused. - typedef QHash<unsigned, QSharedPointer<ResourceHolder> >::const_iterator - ResourceHolderIterator; - ResourceHolderIterator end = resourceCandidates.constEnd(); - for (ResourceHolderIterator it = resourceCandidates.constBegin(); it != end ; ++it) - resourcesToRelease->push_back((*it)->returnResource()); + copyMailboxTextures(); m_previousViewportSize = viewportSize; + m_previousSGObjects = SGObjects(); } void DelegatedFrameNode::flushPolygons( base::circular_deque<std::unique_ptr<viz::DrawPolygon>> *polygonQueue, QSGNode *renderPassChain, DelegatedNodeTreeHandler *nodeHandler, - QHash<unsigned, QSharedPointer<ResourceHolder> > &resourceCandidates, + const CompositorResourceTracker *resourceTracker, RenderWidgetHostViewQtDelegate *apiDelegate) { if (polygonQueue->empty()) @@ -1030,7 +784,7 @@ void DelegatedFrameNode::flushPolygons( polygon->TransformToLayerSpace(inverseTransform); handlePolygon(polygon, currentLayerChain, - nodeHandler, resourceCandidates, apiDelegate); + nodeHandler, resourceTracker, apiDelegate); }; viz::BspTree(polygonQueue).TraverseWithActionHandler(&actionHandler); @@ -1040,20 +794,20 @@ void DelegatedFrameNode::handlePolygon( const viz::DrawPolygon *polygon, QSGNode *currentLayerChain, DelegatedNodeTreeHandler *nodeHandler, - QHash<unsigned, QSharedPointer<ResourceHolder> > &resourceCandidates, + const CompositorResourceTracker *resourceTracker, RenderWidgetHostViewQtDelegate *apiDelegate) { const viz::DrawQuad *quad = polygon->original_ref(); if (!polygon->is_split()) { handleQuad(quad, currentLayerChain, - nodeHandler, resourceCandidates, apiDelegate); + nodeHandler, resourceTracker, apiDelegate); } else { std::vector<gfx::QuadF> clipRegionList; polygon->ToQuads2D(&clipRegionList); for (const auto & clipRegion : clipRegionList) handleClippedQuad(quad, clipRegion, currentLayerChain, - nodeHandler, resourceCandidates, apiDelegate); + nodeHandler, resourceTracker, apiDelegate); } } @@ -1062,7 +816,7 @@ void DelegatedFrameNode::handleClippedQuad( const gfx::QuadF &clipRegion, QSGNode *currentLayerChain, DelegatedNodeTreeHandler *nodeHandler, - QHash<unsigned, QSharedPointer<ResourceHolder> > &resourceCandidates, + const CompositorResourceTracker *resourceTracker, RenderWidgetHostViewQtDelegate *apiDelegate) { if (currentLayerChain) { @@ -1080,21 +834,21 @@ void DelegatedFrameNode::handleClippedQuad( currentLayerChain = clipNode; } handleQuad(quad, currentLayerChain, - nodeHandler, resourceCandidates, apiDelegate); + nodeHandler, resourceTracker, apiDelegate); } void DelegatedFrameNode::handleQuad( const viz::DrawQuad *quad, QSGNode *currentLayerChain, DelegatedNodeTreeHandler *nodeHandler, - QHash<unsigned, QSharedPointer<ResourceHolder> > &resourceCandidates, + const CompositorResourceTracker *resourceTracker, RenderWidgetHostViewQtDelegate *apiDelegate) { switch (quad->material) { case viz::DrawQuad::RENDER_PASS: { const viz::RenderPassDrawQuad *renderPassQuad = viz::RenderPassDrawQuad::MaterialCast(quad); if (!renderPassQuad->mask_texture_size.IsEmpty()) { - ResourceHolder *resource = findAndHoldResource(renderPassQuad->mask_resource_id(), resourceCandidates); + const CompositorResource *resource = findAndHoldResource(renderPassQuad->mask_resource_id(), resourceTracker); Q_UNUSED(resource); // FIXME: QTBUG-67652 } QSGLayer *layer = @@ -1107,7 +861,7 @@ void DelegatedFrameNode::handleQuad( } case viz::DrawQuad::TEXTURE_CONTENT: { const viz::TextureDrawQuad *tquad = viz::TextureDrawQuad::MaterialCast(quad); - ResourceHolder *resource = findAndHoldResource(tquad->resource_id(), resourceCandidates); + const CompositorResource *resource = findAndHoldResource(tquad->resource_id(), resourceTracker); QSGTexture *texture = initAndHoldTexture(resource, quad->ShouldDrawWithBlending(), apiDelegate); QSizeF textureSize; @@ -1158,7 +912,7 @@ void DelegatedFrameNode::handleQuad( } case viz::DrawQuad::TILED_CONTENT: { const viz::TileDrawQuad *tquad = viz::TileDrawQuad::MaterialCast(quad); - ResourceHolder *resource = findAndHoldResource(tquad->resource_id(), resourceCandidates); + const CompositorResource *resource = findAndHoldResource(tquad->resource_id(), resourceTracker); nodeHandler->setupTextureContentNode( initAndHoldTexture(resource, quad->ShouldDrawWithBlending(), apiDelegate), toQt(quad->rect), toQt(tquad->tex_coord_rect), @@ -1168,17 +922,17 @@ void DelegatedFrameNode::handleQuad( } case viz::DrawQuad::YUV_VIDEO_CONTENT: { const viz::YUVVideoDrawQuad *vquad = viz::YUVVideoDrawQuad::MaterialCast(quad); - ResourceHolder *yResource = - findAndHoldResource(vquad->y_plane_resource_id(), resourceCandidates); - ResourceHolder *uResource = - findAndHoldResource(vquad->u_plane_resource_id(), resourceCandidates); - ResourceHolder *vResource = - findAndHoldResource(vquad->v_plane_resource_id(), resourceCandidates); - ResourceHolder *aResource = 0; + const CompositorResource *yResource = + findAndHoldResource(vquad->y_plane_resource_id(), resourceTracker); + const CompositorResource *uResource = + findAndHoldResource(vquad->u_plane_resource_id(), resourceTracker); + const CompositorResource *vResource = + findAndHoldResource(vquad->v_plane_resource_id(), resourceTracker); + const CompositorResource *aResource = nullptr; // This currently requires --enable-vp8-alpha-playback and // needs a video with alpha data to be triggered. if (vquad->a_plane_resource_id()) - aResource = findAndHoldResource(vquad->a_plane_resource_id(), resourceCandidates); + aResource = findAndHoldResource(vquad->a_plane_resource_id(), resourceTracker); nodeHandler->setupYUVVideoNode( initAndHoldTexture(yResource, quad->ShouldDrawWithBlending()), @@ -1194,14 +948,13 @@ void DelegatedFrameNode::handleQuad( } case viz::DrawQuad::STREAM_VIDEO_CONTENT: { const viz::StreamVideoDrawQuad *squad = viz::StreamVideoDrawQuad::MaterialCast(quad); - ResourceHolder *resource = findAndHoldResource(squad->resource_id(), resourceCandidates); + const CompositorResource *resource = findAndHoldResource(squad->resource_id(), resourceTracker); MailboxTexture *texture = static_cast<MailboxTexture *>( - initAndHoldTexture(resource, quad->ShouldDrawWithBlending())); - // since this is not default TEXTURE_2D type - texture->setTarget(GL_TEXTURE_EXTERNAL_OES); + initAndHoldTexture(resource, quad->ShouldDrawWithBlending(), apiDelegate, GL_TEXTURE_EXTERNAL_OES)); - nodeHandler->setupStreamVideoNode(texture, toQt(squad->rect), toQt(squad->matrix.matrix()), - currentLayerChain); + QMatrix4x4 qMatrix; + convertToQt(squad->matrix.matrix(), qMatrix); + nodeHandler->setupStreamVideoNode(texture, toQt(squad->rect), qMatrix, currentLayerChain); break; #endif // GL_OES_EGL_image_external #endif // QT_NO_OPENGL @@ -1213,75 +966,105 @@ void DelegatedFrameNode::handleQuad( } } -ResourceHolder *DelegatedFrameNode::findAndHoldResource(unsigned resourceId, QHash<unsigned, QSharedPointer<ResourceHolder> > &candidates) +const CompositorResource *DelegatedFrameNode::findAndHoldResource(unsigned resourceId, const CompositorResourceTracker *resourceTracker) { - // ResourceHolders must survive when the scene graph destroys our node branch - QSharedPointer<ResourceHolder> &resource = m_chromiumCompositorData->resourceHolders[resourceId]; - if (!resource) - resource = candidates.take(resourceId); - Q_ASSERT(resource); - return resource.data(); + return resourceTracker->findResource(resourceId); } -void DelegatedFrameNode::holdResources(const viz::DrawQuad *quad, QHash<unsigned, QSharedPointer<ResourceHolder> > &candidates) +void DelegatedFrameNode::holdResources(const viz::DrawQuad *quad, const CompositorResourceTracker *resourceTracker) { for (auto resource : quad->resources) - findAndHoldResource(resource, candidates); + findAndHoldResource(resource, resourceTracker); } -void DelegatedFrameNode::holdResources(const viz::RenderPass *pass, QHash<unsigned, QSharedPointer<ResourceHolder> > &candidates) +void DelegatedFrameNode::holdResources(const viz::RenderPass *pass, const CompositorResourceTracker *resourceTracker) { for (const auto &quad : pass->quad_list) - holdResources(quad, candidates); + holdResources(quad, resourceTracker); } -QSGTexture *DelegatedFrameNode::initAndHoldTexture(ResourceHolder *resource, bool quadIsAllOpaque, RenderWidgetHostViewQtDelegate *apiDelegate) +template<class Container, class Key> +inline auto &findTexture(Container &map, Container &previousMap, const Key &key) { - // QSGTextures must be destroyed in the scene graph thread as part of the QSGNode tree, - // so we can't store them with the ResourceHolder in m_chromiumCompositorData. - // Hold them through a QSharedPointer solely on the root DelegatedFrameNode of the web view - // and access them through a QWeakPointer from the resource holder to find them later. - m_sgObjects.textureStrongRefs.append(resource->initTexture(quadIsAllOpaque, apiDelegate)); - return m_sgObjects.textureStrongRefs.last().data(); + auto &value = map[key]; + if (value) + return value; + value = previousMap[key]; + return value; } -void DelegatedFrameNode::fetchAndSyncMailboxes(QList<MailboxTexture *> &mailboxesToFetch) +QSGTexture *DelegatedFrameNode::initAndHoldTexture(const CompositorResource *resource, bool hasAlphaChannel, RenderWidgetHostViewQtDelegate *apiDelegate, int target) { -#ifndef QT_NO_OPENGL - QList<gl::TransferableFence> transferredFences; - { - QMutexLocker lock(&m_mutex); - QVector<MailboxTexture *> mailboxesToPull; - mailboxesToPull.reserve(mailboxesToFetch.size()); - - gpu::SyncPointManager *syncPointManager = sync_point_manager(); - scoped_refptr<base::SingleThreadTaskRunner> gpuTaskRunner = gpu_task_runner(); - Q_ASSERT(m_numPendingSyncPoints == 0); - m_numPendingSyncPoints = mailboxesToFetch.count(); - for (MailboxTexture *mailboxTexture : qAsConst(mailboxesToFetch)) { - gpu::SyncToken &syncToken = mailboxTexture->mailboxHolder().sync_token; - const auto task = base::Bind(&DelegatedFrameNode::pullTexture, this, mailboxTexture); - if (!syncPointManager->WaitOutOfOrder(syncToken, std::move(task))) - mailboxesToPull.append(mailboxTexture); - } - if (!mailboxesToPull.isEmpty()) { - auto task = base::BindOnce(&DelegatedFrameNode::pullTextures, this, std::move(mailboxesToPull)); - gpuTaskRunner->PostTask(FROM_HERE, std::move(task)); - } - - m_mailboxesFetchedWaitCond.wait(&m_mutex); - m_textureFences.swap(transferredFences); + QSGTexture::Filtering filtering; + + if (resource->filter == GL_NEAREST) + filtering = QSGTexture::Nearest; + else if (resource->filter == GL_LINEAR) + filtering = QSGTexture::Linear; + else { + // Depends on qtdeclarative fix, see QTBUG-71322 +#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 1) + filtering = QSGTexture::Linear; +#else + filtering = QSGTexture::Nearest; +#endif } - for (gl::TransferableFence sync : qAsConst(transferredFences)) { - // We need to wait on the fences on the Qt current context, and - // can therefore not use GLFence routines that uses a different - // concept of current context. - waitChromiumSync(&sync); - deleteChromiumSync(&sync); + if (resource->is_software) { + QSharedPointer<QSGTexture> &texture = + findTexture(m_sgObjects.bitmapTextures, m_previousSGObjects.bitmapTextures, resource->id); + if (texture) + return texture.data(); + texture = createBitmapTexture(resource, hasAlphaChannel, apiDelegate); + texture->setFiltering(filtering); + return texture.data(); + } else { +#if QT_CONFIG(opengl) + QSharedPointer<MailboxTexture> &texture = + findTexture(m_sgObjects.mailboxTextures, m_previousSGObjects.mailboxTextures, resource->id); + if (texture) + return texture.data(); + texture = createMailboxTexture(resource, hasAlphaChannel, target); + texture->setFiltering(filtering); + return texture.data(); +#else + Q_UNREACHABLE(); + return nullptr; +#endif } +} -#if defined(USE_OZONE) && !defined(QT_NO_OPENGL) +QSharedPointer<QSGTexture> DelegatedFrameNode::createBitmapTexture(const CompositorResource *resource, bool hasAlphaChannel, RenderWidgetHostViewQtDelegate *apiDelegate) +{ + Q_ASSERT(apiDelegate); + viz::SharedBitmap *sharedBitmap = resource->bitmap.get(); + gfx::Size size = resource->size; + + // QSG interprets QImage::hasAlphaChannel meaning that a node should enable blending + // to draw it but Chromium keeps this information in the quads. + // The input format is currently always Format_ARGB32_Premultiplied, so assume that all + // alpha bytes are 0xff if quads aren't requesting blending and avoid the conversion + // from Format_ARGB32_Premultiplied to Format_RGB32 just to get hasAlphaChannel to + // return false. + QImage::Format format = hasAlphaChannel ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32; + QImage image = sharedBitmap + ? QImage(sharedBitmap->pixels(), size.width(), size.height(), format) + : QImage(size.width(), size.height(), format); + return QSharedPointer<QSGTexture>(apiDelegate->createTextureFromImage(image.copy())); +} + +QSharedPointer<MailboxTexture> DelegatedFrameNode::createMailboxTexture(const CompositorResource *resource, bool hasAlphaChannel, int target) +{ +#ifndef QT_NO_OPENGL + return QSharedPointer<MailboxTexture>::create(resource, hasAlphaChannel, target); +#else + Q_UNREACHABLE(); +#endif +} + +void DelegatedFrameNode::copyMailboxTextures() +{ +#if !defined(QT_NO_OPENGL) && defined(USE_OZONE) // Workaround when context is not shared QTBUG-48969 // Make slow copy between two contexts. if (!m_contextShared) { @@ -1296,13 +1079,17 @@ void DelegatedFrameNode::fetchAndSyncMailboxes(QList<MailboxTexture *> &mailboxe GLuint fbo = 0; funcs->glGenFramebuffers(1, &fbo); - for (MailboxTexture *mailboxTexture : qAsConst(mailboxesToFetch)) { + for (const QSharedPointer<MailboxTexture> &mailboxTexture : qAsConst(m_sgObjects.mailboxTextures)) { + if (mailboxTexture->m_ownsTexture) + continue; + // Read texture into QImage from shared context. // Switch to shared context. sharedContext->makeCurrent(m_offsurface.data()); funcs = sharedContext->functions(); QImage img(mailboxTexture->textureSize(), QImage::Format_RGBA8888_Premultiplied); funcs->glBindFramebuffer(GL_FRAMEBUFFER, fbo); + mailboxTexture->m_fence->wait(); funcs->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mailboxTexture->m_textureId, 0); GLenum status = funcs->glCheckFramebufferStatus(GL_FRAMEBUFFER); if (status != GL_FRAMEBUFFER_COMPLETE) { @@ -1336,69 +1123,6 @@ void DelegatedFrameNode::fetchAndSyncMailboxes(QList<MailboxTexture *> &mailboxe currentContext->makeCurrent(surface); } #endif -#else - Q_UNUSED(mailboxesToFetch) -#endif //QT_NO_OPENGL -} - - -void DelegatedFrameNode::pullTextures(DelegatedFrameNode *frameNode, const QVector<MailboxTexture *> textures) -{ -#ifndef QT_NO_OPENGL - gpu::MailboxManager *mailboxManager = mailbox_manager(); - for (MailboxTexture *texture : textures) { - gpu::SyncToken &syncToken = texture->mailboxHolder().sync_token; - if (syncToken.HasData()) - mailboxManager->PullTextureUpdates(syncToken); - texture->fetchTexture(mailboxManager); - --frameNode->m_numPendingSyncPoints; - } - - fenceAndUnlockQt(frameNode); -#else - Q_UNUSED(frameNode) - Q_UNUSED(textures) -#endif -} - -void DelegatedFrameNode::pullTexture(DelegatedFrameNode *frameNode, MailboxTexture *texture) -{ -#ifndef QT_NO_OPENGL - gpu::MailboxManager *mailboxManager = mailbox_manager(); - gpu::SyncToken &syncToken = texture->mailboxHolder().sync_token; - if (syncToken.HasData()) - mailboxManager->PullTextureUpdates(syncToken); - texture->fetchTexture(mailboxManager); - --frameNode->m_numPendingSyncPoints; - - fenceAndUnlockQt(frameNode); -#else - Q_UNUSED(frameNode) - Q_UNUSED(texture) -#endif -} - -void DelegatedFrameNode::fenceAndUnlockQt(DelegatedFrameNode *frameNode) -{ -#ifndef QT_NO_OPENGL - if (!!gl::GLContext::GetCurrent() && gl::GLFence::IsSupported()) { - // Create a fence on the Chromium GPU-thread and context - std::unique_ptr<gl::GLFence> fence = gl::GLFence::Create(); - // But transfer it to something generic since we need to read it using Qt's OpenGL. - frameNode->m_textureFences.append(fence->Transfer()); - } - if (frameNode->m_numPendingSyncPoints == 0) - base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, base::Bind(&DelegatedFrameNode::unlockQt, frameNode)); -#else - Q_UNUSED(frameNode) -#endif -} - -void DelegatedFrameNode::unlockQt(DelegatedFrameNode *frameNode) -{ - QMutexLocker lock(&frameNode->m_mutex); - // Signal preprocess() the textures are ready - frameNode->m_mailboxesFetchedWaitCond.wakeOne(); } } // namespace QtWebEngineCore diff --git a/src/core/delegated_frame_node.h b/src/core/compositor/delegated_frame_node.h index e37ad08a3..34e4ba029 100644 --- a/src/core/delegated_frame_node.h +++ b/src/core/compositor/delegated_frame_node.h @@ -43,15 +43,10 @@ #include "base/containers/circular_deque.h" #include "components/viz/common/quads/compositor_frame.h" #include "components/viz/common/quads/render_pass.h" -#include "components/viz/common/resources/transferable_resource.h" -#include "gpu/command_buffer/service/sync_point_manager.h" -#include "ui/gl/gl_fence.h" -#include <QMutex> -#include <QSGNode> -#include <QSharedData> -#include <QSharedPointer> -#include <QWaitCondition> + +#include <QtCore/QSharedPointer> #include <QtGui/QOffscreenSurface> +#include <QtQuick/QSGTransformNode> #include "chromium_gpu_helper.h" #include "render_widget_host_view_qt_delegate.h" @@ -72,77 +67,60 @@ class DrawPolygon; namespace QtWebEngineCore { +class CompositorResource; +class CompositorResourceTracker; class DelegatedNodeTreeHandler; class MailboxTexture; -class ResourceHolder; - -// Separating this data allows another DelegatedFrameNode to reconstruct the QSGNode tree from the mailbox textures -// and render pass information. -class ChromiumCompositorData : public QSharedData { -public: - ChromiumCompositorData() : frameDevicePixelRatio(1) { } - QHash<unsigned, QSharedPointer<ResourceHolder> > resourceHolders; - viz::CompositorFrame frameData; - viz::CompositorFrame previousFrameData; - qreal frameDevicePixelRatio; -}; class DelegatedFrameNode : public QSGTransformNode { public: DelegatedFrameNode(); ~DelegatedFrameNode(); - void preprocess(); - void commit(ChromiumCompositorData *chromiumCompositorData, std::vector<viz::ReturnedResource> *resourcesToRelease, RenderWidgetHostViewQtDelegate *apiDelegate); + void preprocess() override; + void commit(const viz::CompositorFrame &pendingFrame, const viz::CompositorFrame &committedFrame, const CompositorResourceTracker *resourceTracker, RenderWidgetHostViewQtDelegate *apiDelegate); private: void flushPolygons(base::circular_deque<std::unique_ptr<viz::DrawPolygon> > *polygonQueue, QSGNode *renderPassChain, DelegatedNodeTreeHandler *nodeHandler, - QHash<unsigned, QSharedPointer<ResourceHolder> > &resourceCandidates, + const CompositorResourceTracker *resourceTracker, RenderWidgetHostViewQtDelegate *apiDelegate); void handlePolygon( const viz::DrawPolygon *polygon, QSGNode *currentLayerChain, DelegatedNodeTreeHandler *nodeHandler, - QHash<unsigned, QSharedPointer<ResourceHolder> > &resourceCandidates, + const CompositorResourceTracker *resourceTracker, RenderWidgetHostViewQtDelegate *apiDelegate); void handleClippedQuad( const viz::DrawQuad *quad, const gfx::QuadF &clipRegion, QSGNode *currentLayerChain, DelegatedNodeTreeHandler *nodeHandler, - QHash<unsigned, QSharedPointer<ResourceHolder> > &resourceCandidates, + const CompositorResourceTracker *resourceTracker, RenderWidgetHostViewQtDelegate *apiDelegate); void handleQuad( const viz::DrawQuad *quad, QSGNode *currentLayerChain, DelegatedNodeTreeHandler *nodeHandler, - QHash<unsigned, QSharedPointer<ResourceHolder> > &resourceCandidates, + const CompositorResourceTracker *resourceTracker, RenderWidgetHostViewQtDelegate *apiDelegate); - void fetchAndSyncMailboxes(QList<MailboxTexture *> &mailboxesToFetch); - // Making those callbacks static bypasses base::Bind's ref-counting requirement - // of the this pointer when the callback is a method. - static void pullTexture(DelegatedFrameNode *frameNode, MailboxTexture *mailbox); - static void pullTextures(DelegatedFrameNode *frameNode, const QVector<MailboxTexture *> mailboxes); - static void fenceAndUnlockQt(DelegatedFrameNode *frameNode); - static void unlockQt(DelegatedFrameNode *frameNode); - - ResourceHolder *findAndHoldResource(unsigned resourceId, QHash<unsigned, QSharedPointer<ResourceHolder> > &candidates); - void holdResources(const viz::DrawQuad *quad, QHash<unsigned, QSharedPointer<ResourceHolder> > &candidates); - void holdResources(const viz::RenderPass *pass, QHash<unsigned, QSharedPointer<ResourceHolder> > &candidates); - QSGTexture *initAndHoldTexture(ResourceHolder *resource, bool quadIsAllOpaque, RenderWidgetHostViewQtDelegate *apiDelegate = 0); - - QExplicitlySharedDataPointer<ChromiumCompositorData> m_chromiumCompositorData; + + const CompositorResource *findAndHoldResource(unsigned resourceId, const CompositorResourceTracker *resourceTracker); + void holdResources(const viz::DrawQuad *quad, const CompositorResourceTracker *resourceTracker); + void holdResources(const viz::RenderPass *pass, const CompositorResourceTracker *resourceTracker); + QSGTexture *initAndHoldTexture(const CompositorResource *resource, bool hasAlphaChannel, RenderWidgetHostViewQtDelegate *apiDelegate = 0, int target = -1); + QSharedPointer<QSGTexture> createBitmapTexture(const CompositorResource *resource, bool hasAlphaChannel, RenderWidgetHostViewQtDelegate *apiDelegate); + QSharedPointer<MailboxTexture> createMailboxTexture(const CompositorResource *resource, bool hasAlphaChannel, int target); + + void copyMailboxTextures(); + struct SGObjects { QVector<QPair<int, QSharedPointer<QSGLayer> > > renderPassLayers; QVector<QSharedPointer<QSGRootNode> > renderPassRootNodes; - QVector<QSharedPointer<QSGTexture> > textureStrongRefs; - } m_sgObjects; + QHash<unsigned, QSharedPointer<QSGTexture> > bitmapTextures; + QHash<unsigned, QSharedPointer<MailboxTexture> > mailboxTextures; + } m_sgObjects, m_previousSGObjects; QVector<QSGNode*> m_sceneGraphNodes; - int m_numPendingSyncPoints; - QWaitCondition m_mailboxesFetchedWaitCond; - QMutex m_mutex; - QList<gl::TransferableFence> m_textureFences; #if defined(USE_OZONE) bool m_contextShared; QScopedPointer<QOffscreenSurface> m_offsurface; diff --git a/src/core/stream_video_node.cpp b/src/core/compositor/stream_video_node.cpp index 29922f866..29922f866 100644 --- a/src/core/stream_video_node.cpp +++ b/src/core/compositor/stream_video_node.cpp diff --git a/src/core/stream_video_node.h b/src/core/compositor/stream_video_node.h index 9d937791f..9d937791f 100644 --- a/src/core/stream_video_node.h +++ b/src/core/compositor/stream_video_node.h diff --git a/src/core/yuv_video_node.cpp b/src/core/compositor/yuv_video_node.cpp index 4a436d952..4a436d952 100644 --- a/src/core/yuv_video_node.cpp +++ b/src/core/compositor/yuv_video_node.cpp diff --git a/src/core/yuv_video_node.h b/src/core/compositor/yuv_video_node.h index dca8fa5e2..dca8fa5e2 100644 --- a/src/core/yuv_video_node.h +++ b/src/core/compositor/yuv_video_node.h diff --git a/src/core/config/common.pri b/src/core/config/common.pri index 42cf445df..fce89f576 100644 --- a/src/core/config/common.pri +++ b/src/core/config/common.pri @@ -4,6 +4,7 @@ QT_FOR_CONFIG += webenginecore gn_args += \ use_qt=true \ + closure_compile=false \ is_component_build=false \ is_shared=true \ enable_message_center=false \ @@ -11,15 +12,20 @@ gn_args += \ enable_nacl=false \ enable_remoting=false \ enable_reporting=false \ + enable_swiftshader=false \ + enable_web_auth=false \ enable_web_speech=false \ enable_widevine=true \ has_native_accessibility=false \ + enable_debugallocation=false \ use_allocator_shim=false \ use_allocator=\"none\" \ + use_custom_libcxx=false \ v8_use_external_startup_data=false \ + toolkit_views=false \ treat_warnings_as_errors=false \ - enable_swiftshader=false \ - use_custom_libcxx=false + safe_browsing_mode=0 \ + optimize_webui=false !win32: gn_args += \ use_jumbo_build=true \ @@ -49,11 +55,17 @@ qtConfig(webengine-spellchecker) { qtConfig(webengine-webrtc) { gn_args += enable_webrtc=true } else { - gn_args += enable_webrtc=false + gn_args += enable_webrtc=false audio_processing_in_audio_service_supported=false } qtConfig(webengine-proprietary-codecs): gn_args += proprietary_codecs=true ffmpeg_branding=\"Chrome\" +qtConfig(webengine-extensions) { + gn_args += enable_extensions=true +} else { + gn_args += enable_extensions=false +} + precompile_header { gn_args += enable_precompiled_headers=true } else { @@ -81,6 +93,12 @@ CONFIG(release, debug|release) { CONFIG(debug, debug|release) { gn_args += is_debug=true gn_args += use_debug_fission=false + # MSVC requires iterator debug to always match and Qt has leaves it default on. + msvc: gn_args += enable_iterator_debugging=true + + # We also can not have optimized V8 binaries for MSVC as iterator debugging + # would mismatch. + msvc|v8base_debug: gn_args += v8_optimized_debug=false } !webcore_debug: gn_args += remove_webcore_debug_symbols=true @@ -91,14 +109,10 @@ optimize_size: gn_args += optimize_for_size=true # We don't want to apply sanitizer options to the build tools (GN, dict convert, etc). !host_build { - sanitizer: gn_args += sanitizer_keep_symbols=true sanitize_address: gn_args += is_asan=true sanitize_thread: gn_args += is_tsan=true sanitize_memory: gn_args += is_msan=true - # rtti is required for a specific check of ubsan, -fsanitize=vptr, which uses the runtime - # type information to check that correct derived objects are assigned to base pointers. Without - # rtti, linking would fail at build time. - sanitize_undefined: gn_args += is_ubsan=true use_rtti=true + sanitize_undefined: gn_args += is_ubsan=true is_ubsan_vptr=true } qtConfig(webengine-v8-snapshot) { @@ -113,8 +127,6 @@ qtConfig(webengine-kerberos) { gn_args += use_kerberos=false } -!msvc: gn_args += enable_iterator_debugging=false - ccache { gn_args += cc_wrapper=\"ccache\" } diff --git a/src/core/config/linux.pri b/src/core/config/linux.pri index eaecab3c9..22cb5991f 100644 --- a/src/core/config/linux.pri +++ b/src/core/config/linux.pri @@ -22,15 +22,19 @@ gn_args += \ ozone_auto_platforms=false \ ozone_platform_headless=false \ ozone_platform_external=true \ - ozone_platform=\"qt\" + ozone_platform=\"qt\" \ + ozone_extra_path=\"$$QTWEBENGINE_ROOT/src/core/ozone/ozone_extra.gni\" qtConfig(webengine-embedded-build) { gn_args += is_desktop_linux=false - gn_args += use_gold=false -} else { - !use_gold_linker: gn_args += use_gold=false } +use_gold_linker: gn_args += use_gold=true +else: gn_args += use_gold=false + +use_lld_linker: gn_args += use_lld=true +else: gn_args += use_lld=false + clang { clang_full_path = $$which($${QMAKE_CXX}) # Remove the "/bin/clang++" part. @@ -38,8 +42,8 @@ clang { gn_args += \ is_clang=true \ clang_use_chrome_plugins=false \ - clang_base_path=\"$${clang_prefix}\" \ - use_lld=false + clang_use_default_sample_profile=false \ + clang_base_path=\"$${clang_prefix}\" linux-clang-libc++: gn_args += use_libcxx=true } else { @@ -159,9 +163,21 @@ host_build { gn_args += use_system_libpng=true qtConfig(webengine-printing-and-pdf): gn_args += pdfium_use_system_libpng=true } - qtConfig(webengine-system-jpeg): gn_args += use_system_libjpeg=true - qtConfig(webengine-system-freetype): gn_args += use_system_freetype=true - qtConfig(webengine-system-harfbuzz): gn_args += use_system_harfbuzz=true + qtConfig(webengine-system-jpeg) { + gn_args += use_system_libjpeg=true + } else { + gn_args += use_system_libjpeg=false + } + qtConfig(webengine-system-freetype) { + gn_args += use_system_freetype=true + } else { + gn_args += use_system_freetype=false + } + qtConfig(webengine-system-harfbuzz) { + gn_args += use_system_harfbuzz=true + } else { + gn_args += use_system_harfbuzz=false + } !qtConfig(webengine-system-glib): gn_args += use_glib=false qtConfig(webengine-pulseaudio) { gn_args += use_pulseaudio=true diff --git a/src/core/config/mac_osx.pri b/src/core/config/mac_osx.pri index 4426901cf..e49df90e7 100644 --- a/src/core/config/mac_osx.pri +++ b/src/core/config/mac_osx.pri @@ -28,8 +28,6 @@ gn_args += \ clang_use_chrome_plugins=false \ mac_deployment_target=\"$${QMAKE_MACOSX_DEPLOYMENT_TARGET}\" \ mac_sdk_min=\"$${QMAKE_MAC_SDK_VERSION}\" \ - mac_views_browser=false \ - toolkit_views=false \ use_external_popup_menu=false qtConfig(webengine-spellchecker) { diff --git a/src/core/config/windows.pri b/src/core/config/windows.pri index 730b38a35..385faeed0 100644 --- a/src/core/config/windows.pri +++ b/src/core/config/windows.pri @@ -1,7 +1,6 @@ include(common.pri) gn_args += \ - is_clang=false \ use_sysroot=false \ enable_session_service=false \ ninja_use_custom_environment_files=false \ @@ -9,6 +8,20 @@ gn_args += \ win_linker_timing=true \ com_init_check_hook_disabled=true +clang_cl { + clang_full_path = $$system_path($$which($${QMAKE_CXX})) + # Remove the "\bin\clang-cl.exe" part: + clang_dir = $$dirname(clang_full_path) + clang_prefix = $$join(clang_dir,,,"\..") + gn_args += \ + is_clang=true \ + use_ldd=true \ + clang_use_chrome_plugins=false \ + clang_base_path=\"$$system_path($$clean_path($$clang_prefix))\" +} else { + gn_args += is_clang=false use_lld=false +} + isDeveloperBuild() { gn_args += \ is_win_fastlink=true @@ -71,7 +84,6 @@ msvc { GN_TARGET_CPU = $$gnArch($$QT_ARCH) gn_args += target_cpu=\"$$GN_TARGET_CPU\" - } else { - error("Qt WebEngine for Windows can only be built with the Microsoft Visual Studio C++ compiler") + error("Qt WebEngine for Windows can only be built with a Microsoft Visual Studio C++ compatible compiler") } diff --git a/src/core/configure.json b/src/core/configure.json index b9c920444..be686850b 100644 --- a/src/core/configure.json +++ b/src/core/configure.json @@ -22,11 +22,14 @@ "webengine-pulseaudio": "boolean", "webengine-spellchecker": "boolean", "webengine-native-spellchecker": "boolean", + "webengine-extensions": "boolean", "webengine-webrtc": "boolean", "webengine-geolocation": "boolean", "webengine-v8-snapshot": "boolean", "webengine-webchannel": "boolean", "webengine-kerberos": "boolean", + "webengine-widgets": "boolean", + "webengine-qml": "boolean", "alsa": { "type": "boolean", "name": "webengine-alsa" }, "pulseaudio": { "type": "boolean", "name": "webengine-pulseaudio" }, "ffmpeg": { "type": "enum", "name": "webengine-system-ffmpeg", "values": { "system": "yes", "qt": "no" } }, @@ -36,6 +39,7 @@ "printing-and-pdf": { "type": "boolean", "name": "webengine-printing-and-pdf" }, "proprietary-codecs": { "type": "boolean", "name": "webengine-proprietary-codecs" }, "spellchecker": { "type": "boolean", "name": "webengine-spellchecker" }, + "extensions": { "type": "boolean", "name": "webengine-extensions" }, "webrtc": { "type": "boolean", "name": "webengine-webrtc" } } }, @@ -84,9 +88,9 @@ ] }, "webengine-harfbuzz": { - "label": "harfbuzz >= 1.4.2", + "label": "harfbuzz >= 2.2.0", "sources": [ - { "type": "pkgConfig", "args": "harfbuzz >= 1.4.2" } + { "type": "pkgConfig", "args": "harfbuzz >= 2.2.0" } ] }, "webengine-glib": { @@ -144,9 +148,9 @@ ] }, "webengine-icu": { - "label": "icu >= 53", + "label": "icu >= 63", "sources": [ - { "type": "pkgConfig", "args": "icu-uc >= 53 icu-i18n >= 53" } + { "type": "pkgConfig", "args": "icu-uc >= 63 icu-i18n >= 63" } ] }, "webengine-ffmpeg": { @@ -310,7 +314,8 @@ }, "webengine-glibc": { "label": "glibc > 2.16", - "type": "detectGlibc" + "type": "compile", + "test": "glibc" }, "webengine-libxml2-compatible": { "label" : "compatible system libxml2", @@ -329,6 +334,10 @@ "label": "thumb instruction set", "type": "hasThumbFlag" }, + "webengine-extensions-gcc-version" : { + "label": "GCC 6 or newer", + "type": "hasGcc6OrNewer" + }, "webengine-noexecstack" : { "label": "linker supports -z noexecstack", "type": "linkerSupportsFlag", @@ -553,14 +562,13 @@ "condition": "config.macos && features.webengine-spellchecker", "output": [ "publicFeature" ] }, - "webengine-ui-delegates": { - "label": "UI Delegates", - "output": [ "privateFeature" ] - }, - "webengine-testsupport": { - "label": "Test Support", - "autoDetect": "features.private_tests || call.isTestsInBuildParts", - "output": [ "privateFeature" ] + "webengine-extensions": { + "label": "Extensions", + "purpose": "Enables Chromium extensions within certain limits. Currently used for enabling the pdf viewer.", + "section": "WebEngine", + "condition": "features.webengine-printing-and-pdf && (tests.webengine-extensions-gcc-version || config.clang || !config.gcc)", + "autoDetect": "features.webengine-printing-and-pdf", + "output": [ "publicFeature" ] }, "webengine-webrtc": { "label": "WebRTC", @@ -676,6 +684,19 @@ "condition": "config.linux && features.webengine-embedded-build && arch.arm && tests.webengine-arm-thumb", "output": [ "privateFeature" ] }, + "webengine-widgets": { + "label": "Qt WebEngine Widgets", + "purpose": "Provides WebEngine Widgets support.", + "section": "WebEngine", + "condition": "module.widgets", + "output": [ "privateFeature" ] + }, + "webengine-qml": { + "label": "Qt WebEngine Qml", + "purpose": "Provides WebEngine Qml support.", + "section": "WebEngine", + "output": [ "privateFeature" ] + }, "webengine-full-debug-info": { "label": "Full debug information", "purpose": "Enables debug information for Blink and V8.", @@ -738,8 +759,10 @@ "summary": [ { - "section": "Qt WebEngine", + "section": "Qt WebEngineCore", "entries": [ + "webengine-widgets", + "webengine-qml", "webengine-embedded-build", "webengine-full-debug-info", "webengine-pepper-plugins", @@ -753,6 +776,7 @@ "webengine-webchannel", "webengine-v8-snapshot", "webengine-kerberos", + "webengine-extensions", { "type": "feature", "args": "webengine-ozone-x11", diff --git a/src/core/content_browser_client_qt.cpp b/src/core/content_browser_client_qt.cpp index acd652b15..16945020b 100644 --- a/src/core/content_browser_client_qt.cpp +++ b/src/core/content_browser_client_qt.cpp @@ -39,15 +39,20 @@ #include "content_browser_client_qt.h" -#include "base/json/json_reader.h" #include "base/memory/ptr_util.h" +#include "base/optional.h" #include "base/strings/utf_string_conversions.h" +#include "base/message_loop/message_loop.h" +#include "base/task/post_task.h" +#include "base/threading/thread_restrictions.h" #if QT_CONFIG(webengine_spellchecker) #include "chrome/browser/spellchecker/spell_check_host_chrome_impl.h" #endif +#include "components/guest_view/browser/guest_view_base.h" #include "components/network_hints/browser/network_hints_message_filter.h" #include "content/browser/renderer_host/render_view_host_delegate.h" #include "content/common/url_schemes.h" +#include "content/public/browser/browser_task_traits.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" @@ -65,15 +70,23 @@ #include "content/public/common/service_manager_connection.h" #include "content/public/common/service_names.mojom.h" #include "content/public/common/url_constants.h" +#include "content/public/common/user_agent.h" #include "media/media_buildflags.h" +#include "extensions/buildflags/buildflags.h" #include "mojo/public/cpp/bindings/binding.h" #include "mojo/public/cpp/bindings/binding_set.h" #include "printing/buildflags/buildflags.h" +#include "qtwebengine/browser/qtwebengine_content_browser_overlay_manifest.h" +#include "qtwebengine/browser/qtwebengine_content_renderer_overlay_manifest.h" +#include "qtwebengine/browser/qtwebengine_packaged_service_manifest.h" +#include "qtwebengine/browser/qtwebengine_renderer_manifest.h" #include "net/ssl/client_cert_identity.h" +#include "net/ssl/client_cert_store.h" #include "services/proxy_resolver/proxy_resolver_service.h" #include "services/service_manager/public/cpp/connector.h" #include "services/service_manager/public/cpp/service.h" #include "services/service_manager/sandbox/switches.h" +#include "third_party/blink/public/common/associated_interfaces/associated_interface_registry.h" #include "third_party/blink/public/platform/modules/insecure_input/insecure_input_service.mojom.h" #include "ui/base/resource/resource_bundle.h" #include "ui/base/ui_base_switches.h" @@ -83,6 +96,7 @@ #include "ui/gl/gpu_timing.h" #include "url/url_util_qt.h" +#include "qtwebengine/common/renderer_configuration.mojom.h" #include "qtwebengine/grit/qt_webengine_resources.h" #include "profile_adapter.h" @@ -95,12 +109,13 @@ #include "login_delegate_qt.h" #include "media_capture_devices_dispatcher.h" #include "net/network_delegate_qt.h" -#include "net/qrc_protocol_handler_qt.h" #include "net/url_request_context_getter_qt.h" +#include "platform_notification_service_qt.h" #if QT_CONFIG(webengine_printing_and_pdf) #include "printing/printing_message_filter_qt.h" #endif #include "profile_qt.h" +#include "profile_io_data_qt.h" #include "quota_permission_context_qt.h" #include "renderer_host/user_resource_controller_host.h" #include "service/service_qt.h" @@ -114,18 +129,6 @@ #include "ui/base/resource/resource_bundle.h" #endif -#if defined(USE_NSS_CERTS) -#include "net/ssl/client_cert_store_nss.h" -#endif - -#if defined(OS_WIN) -#include "net/ssl/client_cert_store_win.h" -#endif - -#if defined(OS_MACOSX) -#include "net/ssl/client_cert_store_mac.h" -#endif - #if QT_CONFIG(webengine_pepper_plugins) #include "content/public/browser/browser_ppapi_host.h" #include "ppapi/host/ppapi_host.h" @@ -136,6 +139,16 @@ #include "location_provider_qt.h" #endif +#if BUILDFLAG(ENABLE_EXTENSIONS) +#include "extensions/extensions_browser_client_qt.h" +#include "extensions/browser/extension_message_filter.h" +#include "extensions/browser/guest_view/extensions_guest_view_message_filter.h" +#include "extensions/browser/io_thread_extension_message_filter.h" +#include "extensions/common/constants.h" +#include "common/extensions/extensions_client_qt.h" +#include "renderer_host/resource_dispatcher_host_delegate_qt.h" +#endif + #include <QGuiApplication> #include <QLocale> #ifndef QT_NO_OPENGL @@ -157,7 +170,7 @@ public: { QString platform = qApp->platformName().toLower(); QPlatformNativeInterface *pni = QGuiApplication::platformNativeInterface(); - if (platform == QLatin1String("xcb")) { + if (platform == QLatin1String("xcb") || platform == QLatin1String("offscreen")) { if (gl::GetGLImplementation() == gl::kGLImplementationEGLGLES2) m_handle = pni->nativeResourceForContext(QByteArrayLiteral("eglcontext"), qtContext); else @@ -248,10 +261,10 @@ void ContentBrowserClientQt::RenderProcessWillLaunch(content::RenderProcessHost* { const int id = host->GetID(); Profile *profile = Profile::FromBrowserContext(host->GetBrowserContext()); - content::BrowserThread::PostTaskAndReplyWithResult( - content::BrowserThread::IO, FROM_HERE, - base::Bind(&net::URLRequestContextGetter::GetURLRequestContext, base::Unretained(profile->GetRequestContext())), - base::Bind(&ContentBrowserClientQt::AddNetworkHintsMessageFilter, base::Unretained(this), id)); + base::PostTaskWithTraitsAndReplyWithResult( + FROM_HERE, {content::BrowserThread::IO}, + base::BindOnce(&net::URLRequestContextGetter::GetURLRequestContext, base::Unretained(profile->GetRequestContext())), + base::BindOnce(&ContentBrowserClientQt::AddNetworkHintsMessageFilter, base::Unretained(this), id)); // FIXME: Add a settings variable to enable/disable the file scheme. content::ChildProcessSecurityPolicy::GetInstance()->GrantRequestScheme(id, url::kFileScheme); @@ -260,21 +273,36 @@ void ContentBrowserClientQt::RenderProcessWillLaunch(content::RenderProcessHost* #if QT_CONFIG(webengine_printing_and_pdf) host->AddFilter(new PrintingMessageFilterQt(host->GetID())); #endif +#if BUILDFLAG(ENABLE_EXTENSIONS) + host->AddFilter(new extensions::ExtensionMessageFilter(host->GetID(), host->GetBrowserContext())); + host->AddFilter(new extensions::IOThreadExtensionMessageFilter(host->GetID(), host->GetBrowserContext())); + host->AddFilter(new extensions::ExtensionsGuestViewMessageFilter(host->GetID(), host->GetBrowserContext())); +#endif //ENABLE_EXTENSIONS + + bool is_incognito_process = profile->IsOffTheRecord(); + qtwebengine::mojom::RendererConfigurationAssociatedPtr renderer_configuration; + host->GetChannel()->GetRemoteAssociatedInterface(&renderer_configuration); + renderer_configuration->SetInitialConfiguration(is_incognito_process); service_manager::mojom::ServicePtr service; *service_request = mojo::MakeRequest(&service); service_manager::mojom::PIDReceiverPtr pid_receiver; service_manager::Identity renderer_identity = host->GetChildIdentity(); - ServiceQt::GetInstance()->connector()->StartService( + ServiceQt::GetInstance()->connector()->RegisterServiceInstance( service_manager::Identity("qtwebengine_renderer", - renderer_identity.user_id(), - renderer_identity.instance()), + renderer_identity.instance_group(), + renderer_identity.instance_id(), + base::Token::CreateRandom()), std::move(service), mojo::MakeRequest(&pid_receiver)); } void ContentBrowserClientQt::ResourceDispatcherHostCreated() { +#if BUILDFLAG(ENABLE_EXTENSIONS) + m_resourceDispatcherHostDelegate.reset(new ResourceDispatcherHostDelegateQt); +#else m_resourceDispatcherHostDelegate.reset(new content::ResourceDispatcherHostDelegate); +#endif content::ResourceDispatcherHost::Get()->SetDelegate(m_resourceDispatcherHostDelegate.get()); } @@ -293,6 +321,10 @@ content::MediaObserver *ContentBrowserClientQt::GetMediaObserver() void ContentBrowserClientQt::OverrideWebkitPrefs(content::RenderViewHost *rvh, content::WebPreferences *web_prefs) { if (content::WebContents *webContents = rvh->GetDelegate()->GetAsWebContents()) { +#if BUILDFLAG(ENABLE_EXTENSIONS) + if (guest_view::GuestViewBase::IsGuest(webContents)) + return; +#endif // BUILDFLAG(ENABLE_EXTENSIONS) WebContentsDelegateQt* delegate = static_cast<WebContentsDelegateQt*>(webContents->GetDelegate()); if (delegate) delegate->overrideWebPreferences(webContents, web_prefs); @@ -382,17 +414,8 @@ std::unique_ptr<net::ClientCertStore> ContentBrowserClientQt::CreateClientCertSt { if (!resource_context) return nullptr; -#if defined(USE_NSS_CERTS) - // FIXME: Give it a proper callback for a password delegate. - return std::unique_ptr<net::ClientCertStore>( - new net::ClientCertStoreNSS(net::ClientCertStoreNSS::PasswordDelegateFactory())); -#elif defined(OS_WIN) - return std::unique_ptr<net::ClientCertStore>(new net::ClientCertStoreWin()); -#elif defined(OS_MACOSX) - return std::unique_ptr<net::ClientCertStore>(new net::ClientCertStoreMac()); -#else - return nullptr; -#endif + + return ProfileIODataQt::FromResourceContext(resource_context)->CreateClientCertStore(); } std::string ContentBrowserClientQt::GetApplicationLocale() @@ -421,6 +444,11 @@ void ContentBrowserClientQt::GetAdditionalWebUISchemes(std::vector<std::string>* additional_schemes->push_back(content::kChromeDevToolsScheme); } +void ContentBrowserClientQt::GetAdditionalViewSourceSchemes(std::vector<std::string>* additional_schemes) +{ + additional_schemes->push_back(content::kChromeDevToolsScheme); +} + #if defined(Q_OS_LINUX) void ContentBrowserClientQt::GetAdditionalMappedFilesForChildProcess(const base::CommandLine& command_line, int child_process_id, content::PosixFileDescriptorInfo* mappings) { @@ -441,7 +469,7 @@ void ContentBrowserClientQt::GetAdditionalMappedFilesForChildProcess(const base: void ContentBrowserClientQt::DidCreatePpapiPlugin(content::BrowserPpapiHost* browser_host) { browser_host->GetPpapiHost()->AddHostFactoryFilter( - base::WrapUnique(new QtWebEngineCore::PepperHostFactoryQt(browser_host))); + std::make_unique<QtWebEngineCore::PepperHostFactoryQt>(browser_host)); } #endif @@ -450,6 +478,13 @@ content::DevToolsManagerDelegate* ContentBrowserClientQt::GetDevToolsManagerDele return new DevToolsManagerDelegateQt; } +content::PlatformNotificationService *ContentBrowserClientQt::GetPlatformNotificationService() +{ + if (!m_platformNotificationService) + m_platformNotificationService = std::make_unique<PlatformNotificationServiceQt>(); + return m_platformNotificationService.get(); +} + // This is a really complicated way of doing absolutely nothing, but Mojo demands it: class ServiceDriver : public blink::mojom::InsecureInputService @@ -485,19 +520,18 @@ public: } // blink::mojom::InsecureInputService: - void PasswordFieldVisibleInInsecureContext() override - { } - void AllPasswordFieldsInInsecureContextInvisible() override - { } void DidEditFieldInInsecureContext() override { } private: + WEB_CONTENTS_USER_DATA_KEY_DECL() explicit ServiceDriver(content::WebContents* /*web_contents*/) { } friend class content::WebContentsUserData<ServiceDriver>; mojo::BindingSet<blink::mojom::InsecureInputService> m_insecureInputServiceBindings; }; +WEB_CONTENTS_USER_DATA_KEY_IMPL(ServiceDriver) + void ContentBrowserClientQt::InitFrameInterfaces() { m_frameInterfaces = std::make_unique<service_manager::BinderRegistry>(); @@ -516,11 +550,11 @@ void ContentBrowserClientQt::BindInterfaceRequestFromFrame(content::RenderFrameH m_frameInterfaces->TryBindInterface(interface_name, &interface_pipe); } -void ContentBrowserClientQt::RegisterInProcessServices(StaticServiceMap* services, content::ServiceManagerConnection* connection) +void ContentBrowserClientQt::RegisterIOThreadServiceHandlers(content::ServiceManagerConnection *connection) { - service_manager::EmbeddedServiceInfo info; - info.factory = ServiceQt::GetInstance()->CreateServiceQtFactory(); - services->insert(std::make_pair("qtwebengine", info)); + connection->AddServiceRequestHandler( + "qtwebengine", + ServiceQt::GetInstance()->CreateServiceQtRequestHandler()); } void ContentBrowserClientQt::RegisterOutOfProcessServices(content::ContentBrowserClient::OutOfProcessServiceMap *services) @@ -529,46 +563,41 @@ void ContentBrowserClientQt::RegisterOutOfProcessServices(content::ContentBrowse base::BindRepeating(&base::ASCIIToUTF16, "V8 Proxy Resolver"); } -std::unique_ptr<base::Value> ContentBrowserClientQt::GetServiceManifestOverlay(base::StringPiece name) +base::Optional<service_manager::Manifest> ContentBrowserClientQt::GetServiceManifestOverlay(base::StringPiece name) { - ui::ResourceBundle &rb = ui::ResourceBundle::GetSharedInstance(); - int id = -1; - if (name == content::mojom::kPackagedServicesServiceName) - id = IDR_QTWEBENGINE_CONTENT_PACKAGED_SERVICES_MANIFEST_OVERLAY; - else if (name == content::mojom::kRendererServiceName) - id = IDR_QTWEBENGINE_CONTENT_RENDERER_MANIFEST_OVERLAY; - else if (name == content::mojom::kBrowserServiceName) - id = IDR_QTWEBENGINE_CONTENT_BROWSER_MANIFEST_OVERLAY; - if (id == -1) - return nullptr; + if (name == content::mojom::kBrowserServiceName) { + return GetQtWebEngineContentBrowserOverlayManifest(); + } else if (name == content::mojom::kPackagedServicesServiceName) { + service_manager::Manifest overlay; + overlay.packaged_services = GetQtWebEnginePackagedServiceManifests(); + return overlay; + } else if (name == content::mojom::kRendererServiceName) { + return GetQtWebEngineContentRendererOverlayManifest(); + } - base::StringPiece manifest_contents = - rb.GetRawDataResourceForScale(id, ui::ScaleFactor::SCALE_FACTOR_NONE); - return base::JSONReader::Read(manifest_contents); + return base::nullopt; } -std::vector<content::ContentBrowserClient::ServiceManifestInfo> ContentBrowserClientQt::GetExtraServiceManifests() +std::vector<service_manager::Manifest> ContentBrowserClientQt::GetExtraServiceManifests() { - return std::vector<content::ContentBrowserClient::ServiceManifestInfo>({ - {"qtwebengine_renderer", IDR_QTWEBENGINE_RENDERER_SERVICE_MANIFEST}, - }); + return std::vector<service_manager::Manifest>{GetQtWebEngineRendererManifest()}; } bool ContentBrowserClientQt::CanCreateWindow( - content::RenderFrameHost* opener, - const GURL& opener_url, - const GURL& opener_top_level_frame_url, - const GURL& source_origin, - content::mojom::WindowContainerType container_type, - const GURL& target_url, - const content::Referrer& referrer, - const std::string& frame_name, - WindowOpenDisposition disposition, - const blink::mojom::WindowFeatures& features, - bool user_gesture, - bool opener_suppressed, - bool* no_javascript_access) { - + content::RenderFrameHost* opener, + const GURL& opener_url, + const GURL& opener_top_level_frame_url, + const url::Origin& source_origin, + content::mojom::WindowContainerType container_type, + const GURL& target_url, + const content::Referrer& referrer, + const std::string& frame_name, + WindowOpenDisposition disposition, + const blink::mojom::WindowFeatures& features, + bool user_gesture, + bool opener_suppressed, + bool* no_javascript_access) +{ Q_UNUSED(opener_url); Q_UNUSED(opener_top_level_frame_url); Q_UNUSED(source_origin); @@ -618,11 +647,18 @@ void ContentBrowserClientQt::AddNetworkHintsMessageFilter(int render_process_id, if (!host) return; - content::BrowserMessageFilter *network_hints_message_filter( - new network_hints::NetworkHintsMessageFilter(context->host_resolver())); + content::BrowserMessageFilter *network_hints_message_filter = + new network_hints::NetworkHintsMessageFilter(render_process_id); host->AddFilter(network_hints_message_filter); } +bool ContentBrowserClientQt::ShouldEnableStrictSiteIsolation() +{ + // mirroring AwContentBrowserClient, CastContentBrowserClient and + // HeadlessContentBrowserClient + return false; +} + bool ContentBrowserClientQt::AllowGetCookie(const GURL &url, const GURL &first_party, const net::CookieList & /*cookie_list*/, @@ -631,8 +667,7 @@ bool ContentBrowserClientQt::AllowGetCookie(const GURL &url, int /*render_frame_id*/) { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - NetworkDelegateQt *networkDelegate = static_cast<NetworkDelegateQt *>(context->GetRequestContext()->network_delegate()); - return networkDelegate->canGetCookies(first_party, url); + return ProfileIODataQt::FromResourceContext(context)->canGetCookies(toQt(first_party), toQt(url)); } bool ContentBrowserClientQt::AllowSetCookie(const GURL &url, @@ -643,8 +678,7 @@ bool ContentBrowserClientQt::AllowSetCookie(const GURL &url, int /*render_frame_id*/) { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - NetworkDelegateQt *networkDelegate = static_cast<NetworkDelegateQt *>(context->GetRequestContext()->network_delegate()); - return networkDelegate->canSetCookies(first_party, url, std::string()); + return ProfileIODataQt::FromResourceContext(context)->canSetCookie(toQt(first_party), QByteArray(), toQt(url)); } bool ContentBrowserClientQt::AllowAppCache(const GURL &manifest_url, @@ -652,41 +686,37 @@ bool ContentBrowserClientQt::AllowAppCache(const GURL &manifest_url, content::ResourceContext *context) { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - NetworkDelegateQt *networkDelegate = static_cast<NetworkDelegateQt *>(context->GetRequestContext()->network_delegate()); - return networkDelegate->canGetCookies(first_party, manifest_url); + return ProfileIODataQt::FromResourceContext(context)->canGetCookies(toQt(first_party), toQt(manifest_url)); } bool ContentBrowserClientQt::AllowServiceWorker(const GURL &scope, const GURL &first_party, content::ResourceContext *context, - const base::Callback<content::WebContents*(void)> &/*wc_getter*/) + base::RepeatingCallback<content::WebContents*()> wc_getter) { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); // FIXME: Chrome also checks if javascript is enabled here to check if has been disabled since the service worker // was started. - NetworkDelegateQt *networkDelegate = static_cast<NetworkDelegateQt *>(context->GetRequestContext()->network_delegate()); - return networkDelegate->canGetCookies(first_party, scope); + return ProfileIODataQt::FromResourceContext(context)->canGetCookies(toQt(first_party), toQt(scope)); } // We control worker access to FS and indexed-db using cookie permissions, this is mirroring Chromium's logic. void ContentBrowserClientQt::AllowWorkerFileSystem(const GURL &url, content::ResourceContext *context, - const std::vector<std::pair<int, int> > &/*render_frames*/, + const std::vector<content::GlobalFrameRoutingId> &/*render_frames*/, base::Callback<void(bool)> callback) { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - NetworkDelegateQt *networkDelegate = static_cast<NetworkDelegateQt *>(context->GetRequestContext()->network_delegate()); - callback.Run(networkDelegate->canSetCookies(url, url, std::string())); + callback.Run(ProfileIODataQt::FromResourceContext(context)->canSetCookie(toQt(url), QByteArray(), toQt(url))); } + bool ContentBrowserClientQt::AllowWorkerIndexedDB(const GURL &url, - const base::string16 &/*name*/, content::ResourceContext *context, - const std::vector<std::pair<int, int> > &/*render_frames*/) + const std::vector<content::GlobalFrameRoutingId> &/*render_frames*/) { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - NetworkDelegateQt *networkDelegate = static_cast<NetworkDelegateQt *>(context->GetRequestContext()->network_delegate()); - return networkDelegate->canSetCookies(url, url, std::string()); + return ProfileIODataQt::FromResourceContext(context)->canSetCookie(toQt(url), QByteArray(), toQt(url)); } static void LaunchURL(const GURL& url, @@ -709,21 +739,23 @@ bool ContentBrowserClientQt::HandleExternalProtocol( content::NavigationUIData *navigation_data, bool is_main_frame, ui::PageTransition page_transition, - bool has_user_gesture) + bool has_user_gesture, + const std::string &method, + const net::HttpRequestHeaders &headers) { Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); Q_UNUSED(child_id); Q_UNUSED(navigation_data); - - content::BrowserThread::PostTask( - content::BrowserThread::UI, - FROM_HERE, - base::BindOnce(&LaunchURL, - url, - web_contents_getter, - page_transition, - is_main_frame, - has_user_gesture)); + Q_UNUSED(method); + Q_UNUSED(headers); + + base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(&LaunchURL, + url, + web_contents_getter, + page_transition, + is_main_frame, + has_user_gesture)); return true; } @@ -737,9 +769,36 @@ scoped_refptr<content::LoginDelegate> ContentBrowserClientQt::CreateLoginDelegat bool first_auth_attempt, LoginAuthRequiredCallback auth_required_callback) { - return base::MakeRefCounted<LoginDelegateQt>(authInfo, web_contents_getter, url, first_auth_attempt, std::move(auth_required_callback)); + auto loginDelegate = base::MakeRefCounted<LoginDelegateQt>(authInfo, web_contents_getter, url, first_auth_attempt, std::move(auth_required_callback)); + loginDelegate->triggerDialog(); + return loginDelegate; } -} // namespace QtWebEngineCore +bool ContentBrowserClientQt::ShouldIsolateErrorPage(bool in_main_frame) +{ + Q_UNUSED(in_main_frame); + return false; +} -DEFINE_WEB_CONTENTS_USER_DATA_KEY(QtWebEngineCore::ServiceDriver); +bool ContentBrowserClientQt::ShouldUseProcessPerSite(content::BrowserContext* browser_context, const GURL& effective_url) +{ +#if BUILDFLAG(ENABLE_EXTENSIONS) + if (effective_url.SchemeIs(extensions::kExtensionScheme)) + return true; +#endif + return ContentBrowserClient::ShouldUseProcessPerSite(browser_context, effective_url); +} + +std::string ContentBrowserClientQt::getUserAgent() +{ + // Mention the Chromium version we're based on to get passed stupid UA-string-based feature detection (several WebRTC demos need this) + return content::BuildUserAgentFromProduct("QtWebEngine/" QTWEBENGINECORE_VERSION_STR " Chrome/" CHROMIUM_VERSION); +} + +std::string ContentBrowserClientQt::GetProduct() const +{ + QString productName(qApp->applicationName() % '/' % qApp->applicationVersion()); + return productName.toStdString(); +} + +} // namespace QtWebEngineCore diff --git a/src/core/content_browser_client_qt.h b/src/core/content_browser_client_qt.h index b2761b311..0b1c134cc 100644 --- a/src/core/content_browser_client_qt.h +++ b/src/core/content_browser_client_qt.h @@ -108,33 +108,36 @@ public: std::unique_ptr<content::ClientCertificateDelegate> delegate) override; std::unique_ptr<net::ClientCertStore> CreateClientCertStore(content::ResourceContext *resource_context) override; content::DevToolsManagerDelegate *GetDevToolsManagerDelegate() override; + content::PlatformNotificationService *GetPlatformNotificationService() override; std::string GetApplicationLocale() override; std::string GetAcceptLangs(content::BrowserContext* context) override; void AppendExtraCommandLineSwitches(base::CommandLine* command_line, int child_process_id) override; + + void GetAdditionalViewSourceSchemes(std::vector<std::string>* additional_schemes) override; void GetAdditionalWebUISchemes(std::vector<std::string>* additional_schemes) override; void BindInterfaceRequestFromFrame(content::RenderFrameHost* render_frame_host, const std::string& interface_name, mojo::ScopedMessagePipeHandle interface_pipe) override; - void RegisterInProcessServices(StaticServiceMap* services, content::ServiceManagerConnection* connection) override; + void RegisterIOThreadServiceHandlers(content::ServiceManagerConnection *connection) override; void RegisterOutOfProcessServices(OutOfProcessServiceMap* services) override; - std::vector<ServiceManifestInfo> GetExtraServiceManifests() override; - std::unique_ptr<base::Value> GetServiceManifestOverlay(base::StringPiece name) override; - bool CanCreateWindow( - content::RenderFrameHost* opener, - const GURL& opener_url, - const GURL& opener_top_level_frame_url, - const GURL& source_origin, - content::mojom::WindowContainerType container_type, - const GURL& target_url, - const content::Referrer& referrer, - const std::string& frame_name, - WindowOpenDisposition disposition, - const blink::mojom::WindowFeatures& features, - bool user_gesture, - bool opener_suppressed, - bool* no_javascript_access) override; + std::vector<service_manager::Manifest> GetExtraServiceManifests() override; + base::Optional<service_manager::Manifest> GetServiceManifestOverlay(base::StringPiece name) override; + bool CanCreateWindow(content::RenderFrameHost *opener, + const GURL &opener_url, + const GURL &opener_top_level_frame_url, + const url::Origin &source_origin, + content::mojom::WindowContainerType container_type, + const GURL &target_url, + const content::Referrer &referrer, + const std::string &frame_name, + WindowOpenDisposition disposition, + const blink::mojom::WindowFeatures &features, + bool user_gesture, + bool opener_suppressed, + bool *no_javascript_access) override; + bool ShouldEnableStrictSiteIsolation() override; bool AllowGetCookie(const GURL& url, const GURL& first_party, @@ -157,21 +160,22 @@ public: bool AllowServiceWorker(const GURL& scope, const GURL& first_party, content::ResourceContext* context, - const base::Callback<content::WebContents*(void)>& wc_getter) override; + base::RepeatingCallback<content::WebContents*()> wc_getter) override; void AllowWorkerFileSystem(const GURL &url, content::ResourceContext *context, - const std::vector<std::pair<int, int> > &render_frames, + const std::vector<content::GlobalFrameRoutingId> &render_frames, base::Callback<void(bool)> callback) override; bool AllowWorkerIndexedDB(const GURL &url, - const base::string16 &name, content::ResourceContext *context, - const std::vector<std::pair<int, int> > &render_frames) override; + const std::vector<content::GlobalFrameRoutingId> &render_frames) override; #if QT_CONFIG(webengine_geolocation) std::unique_ptr<device::LocationProvider> OverrideSystemLocationProvider() override; #endif + bool ShouldIsolateErrorPage(bool in_main_frame) override; + bool ShouldUseProcessPerSite(content::BrowserContext* browser_context, const GURL& effective_url) override; #if defined(Q_OS_LINUX) void GetAdditionalMappedFilesForChildProcess(const base::CommandLine& command_line, int child_process_id, content::PosixFileDescriptorInfo* mappings) override; @@ -194,10 +198,17 @@ public: const GURL &url, content::ResourceRequestInfo::WebContentsGetter web_contents_getter, int child_id, - content::NavigationUIData *navigation_data, + content::NavigationUIData *navigation_data, bool is_main_frame, ui::PageTransition page_transition, - bool has_user_gesture) override; + bool has_user_gesture, + const std::string &method, + const net::HttpRequestHeaders &headers) override; + + static std::string getUserAgent(); + + std::string GetUserAgent() const override { return getUserAgent(); } + std::string GetProduct() const override; private: void InitFrameInterfaces(); @@ -205,6 +216,7 @@ private: BrowserMainPartsQt* m_browserMainParts; std::unique_ptr<content::ResourceDispatcherHostDelegate> m_resourceDispatcherHostDelegate; + std::unique_ptr<content::PlatformNotificationService> m_platformNotificationService; scoped_refptr<ShareGroupQtQuick> m_shareGroupQtQuick; std::unique_ptr<service_manager::BinderRegistry> m_frameInterfaces; std::unique_ptr<service_manager::BinderRegistryWithArgs<content::RenderFrameHost*>> m_frameInterfacesParameterized; diff --git a/src/core/content_client_qt.cpp b/src/core/content_client_qt.cpp index df1bc303d..8e5fdf06c 100644 --- a/src/core/content_client_qt.cpp +++ b/src/core/content_client_qt.cpp @@ -48,7 +48,6 @@ #include "base/version.h" #include "content/public/common/cdm_info.h" #include "content/public/common/content_constants.h" -#include "content/public/common/user_agent.h" #include "media/base/media_switches.h" #include "media/base/video_codecs.h" #include "media/media_buildflags.h" @@ -56,7 +55,6 @@ #include "ui/base/l10n/l10n_util.h" #include "ui/base/resource/resource_bundle.h" -#include "net/qrc_protocol_handler_qt.h" #include "type_conversion.h" #include <QCoreApplication> @@ -66,10 +64,9 @@ #if BUILDFLAG(ENABLE_LIBRARY_CDMS) #include "media/cdm/cdm_paths.h" // nogncheck +#include "third_party/widevine/cdm/buildflags.h" #include "third_party/widevine/cdm/widevine_cdm_common.h" -#include "widevine_cdm_version.h" // In SHARED_INTERMEDIATE_DIR. -#define WIDEVINE_CDM_AVAILABLE -#if defined(WIDEVINE_CDM_AVAILABLE) && !defined(WIDEVINE_CDM_IS_COMPONENT) +#if BUILDFLAG(ENABLE_WIDEVINE) && !BUILDFLAG(ENABLE_WIDEVINE_CDM_COMPONENT) #define WIDEVINE_CDM_AVAILABLE_NOT_COMPONENT namespace switches { const char kCdmWidevinePath[] = "widevine-path"; @@ -85,6 +82,14 @@ const char kWidevineCdmFileName[] = #endif #endif +#if QT_CONFIG(webengine_printing_and_pdf) +#include "pdf/pdf.h" +#include "pdf/pdf_ppapi.h" +const char kPdfPluginMimeType[] = "application/x-google-chrome-pdf"; +const char kPdfPluginPath[] = "internal-pdf-viewer/"; +const char kPdfPluginSrc[] = "src"; +#endif // QT_CONFIG(webengine_printing_and_pdf) + static QString webenginePluginsPath() { // Look for plugins in /plugins/webengine or application dir. @@ -99,7 +104,6 @@ static QString webenginePluginsPath() } #endif // BUILDFLAG(ENABLE_LIBRARY_CDMS) - #if defined(Q_OS_WIN) #include <shlobj.h> static QString getLocalAppDataDir() @@ -235,10 +239,30 @@ void AddPepperFlashFromCommandLine(std::vector<content::PepperPluginInfo>* plugi plugins->push_back(CreatePepperFlashInfo(base::FilePath(flash_path), flash_version)); } +void ComputeBuiltInPlugins(std::vector<content::PepperPluginInfo>* plugins) +{ +#if QT_CONFIG(webengine_printing_and_pdf) + content::PepperPluginInfo pdf_info; + pdf_info.is_internal = true; + pdf_info.is_out_of_process = true; + pdf_info.name = "Chromium PDF Viewer"; + pdf_info.description = "Portable Document Format"; + pdf_info.path = base::FilePath::FromUTF8Unsafe(kPdfPluginPath); + content::WebPluginMimeType pdf_mime_type(kPdfPluginMimeType, "pdf", "Portable Document Format"); + pdf_info.mime_types.push_back(pdf_mime_type); + pdf_info.internal_entry_points.get_interface = chrome_pdf::PPP_GetInterface; + pdf_info.internal_entry_points.initialize_module = chrome_pdf::PPP_InitializeModule; + pdf_info.internal_entry_points.shutdown_module = chrome_pdf::PPP_ShutdownModule; + pdf_info.permissions = ppapi::PERMISSION_PRIVATE | ppapi::PERMISSION_DEV | ppapi::PERMISSION_PDF; + plugins->push_back(pdf_info); +#endif // QT_CONFIG(webengine_printing_and_pdf) +} + namespace QtWebEngineCore { void ContentClientQt::AddPepperPlugins(std::vector<content::PepperPluginInfo>* plugins) { + ComputeBuiltInPlugins(plugins); AddPepperFlashFromSystem(plugins); AddPepperFlashFromCommandLine(plugins); } @@ -330,7 +354,6 @@ static bool IsWidevineAvailable(base::FilePath *cdm_path, } #endif // defined(WIDEVINE_CDM_AVAILABLE_NOT_COMPONENT) - void ContentClientQt::AddContentDecryptionModules(std::vector<content::CdmInfo> *cdms, std::vector<media::CdmHostFilePath> *cdm_host_file_paths) { @@ -386,10 +409,9 @@ void ContentClientQt::AddContentDecryptionModules(std::vector<content::CdmInfo> } } -std::string ContentClientQt::getUserAgent() +void ContentClientQt::AddAdditionalSchemes(Schemes* schemes) { - // Mention the Chromium version we're based on to get passed stupid UA-string-based feature detection (several WebRTC demos need this) - return content::BuildUserAgentFromProduct("QtWebEngine/" QTWEBENGINECORE_VERSION_STR " Chrome/" CHROMIUM_VERSION); + schemes->standard_schemes.push_back("chrome-extension"); } base::StringPiece ContentClientQt::GetDataResource(int resource_id, ui::ScaleFactor scale_factor) const { @@ -401,15 +423,14 @@ base::RefCountedMemory *ContentClientQt::GetDataResourceBytes(int resource_id) c return ui::ResourceBundle::GetSharedInstance().LoadDataResourceBytes(resource_id); } -base::string16 ContentClientQt::GetLocalizedString(int message_id) const +gfx::Image &ContentClientQt::GetNativeImageNamed(int resource_id) const { - return l10n_util::GetStringUTF16(message_id); + return ui::ResourceBundle::GetSharedInstance().GetNativeImageNamed(resource_id); } -std::string ContentClientQt::GetProduct() const +base::string16 ContentClientQt::GetLocalizedString(int message_id) const { - QString productName(qApp->applicationName() % '/' % qApp->applicationVersion()); - return productName.toStdString(); + return l10n_util::GetStringUTF16(message_id); } } // namespace QtWebEngineCore diff --git a/src/core/content_client_qt.h b/src/core/content_client_qt.h index fbafa6a4b..1f4ac0b63 100644 --- a/src/core/content_client_qt.h +++ b/src/core/content_client_qt.h @@ -49,19 +49,17 @@ namespace QtWebEngineCore { class ContentClientQt : public content::ContentClient { public: - static std::string getUserAgent(); - #if QT_CONFIG(webengine_pepper_plugins) void AddPepperPlugins(std::vector<content::PepperPluginInfo>* plugins) override; #endif void AddContentDecryptionModules(std::vector<content::CdmInfo> *cdms, std::vector<media::CdmHostFilePath> *cdm_host_file_paths) override; + void AddAdditionalSchemes(Schemes* schemes) override; base::StringPiece GetDataResource(int, ui::ScaleFactor) const override; - base::RefCountedMemory* GetDataResourceBytes(int resource_id) const override; - std::string GetUserAgent() const override { return getUserAgent(); } + base::RefCountedMemory* GetDataResourceBytes(int resource_id) const override; + gfx::Image &GetNativeImageNamed(int resource_id) const override; base::string16 GetLocalizedString(int message_id) const override; - std::string GetProduct() const override; }; } // namespace QtWebEngineCore diff --git a/src/core/content_main_delegate_qt.cpp b/src/core/content_main_delegate_qt.cpp index 2811d5545..57f8af63c 100644 --- a/src/core/content_main_delegate_qt.cpp +++ b/src/core/content_main_delegate_qt.cpp @@ -40,17 +40,18 @@ #include "content_main_delegate_qt.h" #include "base/command_line.h" -#include <base/i18n/rtl.h> +#include "base/i18n/rtl.h" #include "base/logging.h" #include "base/path_service.h" #include "base/strings/string_number_conversions.h" -#include <chrome/grit/generated_resources.h> +#include "chrome/grit/generated_resources.h" +#include "content/public/browser/browser_main_runner.h" #include "content/public/common/content_paths.h" #include "content/public/common/content_switches.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/ui_base_paths.h" #include "ui/base/resource/resource_bundle.h" -#include <ui/base/webui/jstemplate_builder.h> +#include "ui/base/webui/jstemplate_builder.h" #include "net/grit/net_resources.h" #include "net/base/net_module.h" #include "services/service_manager/sandbox/switches.h" @@ -59,6 +60,7 @@ #include "content_client_qt.h" #include "renderer/content_renderer_client_qt.h" #include "type_conversion.h" +#include "web_engine_context.h" #include "web_engine_library_info.h" #if defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || defined(OS_LINUX)) @@ -71,6 +73,10 @@ #include <QtCore/qcoreapplication.h> +namespace content { +ContentClient *GetContentClient(); +} + namespace QtWebEngineCore { // The logic of this function is based on chrome/common/net/net_resource_provider.cc @@ -167,6 +173,12 @@ content::ContentBrowserClient *ContentMainDelegateQt::CreateContentBrowserClient return m_browserClient.get(); } +content::ContentGpuClient *ContentMainDelegateQt::CreateContentGpuClient() +{ + m_gpuClient.reset(new ContentGpuClientQt); + return m_gpuClient.get(); +} + content::ContentRendererClient *ContentMainDelegateQt::CreateContentRendererClient() { #if defined(OS_LINUX) @@ -214,14 +226,13 @@ static void SafeOverridePathImpl(const char *keyName, int key, const base::FileP bool ContentMainDelegateQt::BasicStartupComplete(int *exit_code) { SafeOverridePath(base::FILE_EXE, WebEngineLibraryInfo::getPath(base::FILE_EXE)); -#if ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE SafeOverridePath(base::DIR_QT_LIBRARY_DATA, WebEngineLibraryInfo::getPath(base::DIR_QT_LIBRARY_DATA)); -#endif SafeOverridePath(ui::DIR_LOCALES, WebEngineLibraryInfo::getPath(ui::DIR_LOCALES)); #if QT_CONFIG(webengine_spellchecker) SafeOverridePath(base::DIR_APP_DICTIONARIES, WebEngineLibraryInfo::getPath(base::DIR_APP_DICTIONARIES)); #endif - SetContentClient(new ContentClientQt); + if (!content::GetContentClient()) + content::SetContentClient(new ContentClientQt); url::CustomScheme::LoadSchemes(base::CommandLine::ForCurrentProcess()); diff --git a/src/core/content_main_delegate_qt.h b/src/core/content_main_delegate_qt.h index c06afb0fb..4d2f33792 100644 --- a/src/core/content_main_delegate_qt.h +++ b/src/core/content_main_delegate_qt.h @@ -42,6 +42,7 @@ #include "content/public/app/content_main_delegate.h" +#include "compositor/content_gpu_client_qt.h" #include "content_browser_client_qt.h" #include "content_utility_client_qt.h" @@ -56,12 +57,14 @@ public: void PreSandboxStartup() override; content::ContentBrowserClient* CreateContentBrowserClient() override; + content::ContentGpuClient* CreateContentGpuClient() override; content::ContentRendererClient* CreateContentRendererClient() override; content::ContentUtilityClient* CreateContentUtilityClient() override; bool BasicStartupComplete(int* /*exit_code*/) override; private: std::unique_ptr<ContentBrowserClientQt> m_browserClient; + std::unique_ptr<ContentGpuClientQt> m_gpuClient; std::unique_ptr<ContentUtilityClientQt> m_utilityClient; }; diff --git a/src/core/content_utility_client_qt.cpp b/src/core/content_utility_client_qt.cpp index f49fa6386..0b2dbd08e 100644 --- a/src/core/content_utility_client_qt.cpp +++ b/src/core/content_utility_client_qt.cpp @@ -39,6 +39,7 @@ #include "content_utility_client_qt.h" +#include "base/bind.h" #include "content/public/utility/utility_thread.h" #include "services/proxy_resolver/proxy_resolver_service.h" @@ -50,12 +51,41 @@ ContentUtilityClientQt::ContentUtilityClientQt() ContentUtilityClientQt::~ContentUtilityClientQt() = default; -void ContentUtilityClientQt::RegisterServices(ContentUtilityClient::StaticServiceMap *services) +namespace { + +std::unique_ptr<service_manager::Service> CreateProxyResolverService(service_manager::mojom::ServiceRequest request) { - service_manager::EmbeddedServiceInfo proxy_resolver_info; - proxy_resolver_info.task_runner = content::ChildThread::Get()->GetIOTaskRunner(); - proxy_resolver_info.factory = base::BindRepeating(&proxy_resolver::ProxyResolverService::CreateService); - services->emplace(proxy_resolver::mojom::kProxyResolverServiceName, proxy_resolver_info); + return std::make_unique<proxy_resolver::ProxyResolverService>(std::move(request)); +} + +using ServiceFactory = base::OnceCallback<std::unique_ptr<service_manager::Service>()>; +void RunServiceOnIOThread(ServiceFactory factory) +{ + base::OnceClosure terminate_process = base::BindOnce( + base::IgnoreResult(&base::SequencedTaskRunner::PostTask), + base::SequencedTaskRunnerHandle::Get(), FROM_HERE, + base::BindOnce([] { content::UtilityThread::Get()->ReleaseProcess(); })); + content::ChildThread::Get()->GetIOTaskRunner()->PostTask( + FROM_HERE, + base::BindOnce( + [](ServiceFactory factory, base::OnceClosure terminate_process) { + service_manager::Service::RunAsyncUntilTermination( + std::move(factory).Run(), std::move(terminate_process)); + }, + std::move(factory), std::move(terminate_process))); +} + +} // namespace + +bool ContentUtilityClientQt::HandleServiceRequest(const std::string &service_name, + service_manager::mojom::ServiceRequest request) +{ + if (service_name == proxy_resolver::mojom::kProxyResolverServiceName) { + RunServiceOnIOThread(base::BindOnce(&CreateProxyResolverService, std::move(request))); + return true; + } + + return false; } } // namespace diff --git a/src/core/content_utility_client_qt.h b/src/core/content_utility_client_qt.h index 3fb7c97d5..79972adb8 100644 --- a/src/core/content_utility_client_qt.h +++ b/src/core/content_utility_client_qt.h @@ -53,7 +53,9 @@ public: ~ContentUtilityClientQt() override; // content::ContentUtilityClient: - void RegisterServices(StaticServiceMap *services) override; + bool HandleServiceRequest(const std::string &service_name, + service_manager::mojom::ServiceRequest request) override; + }; } // namespace diff --git a/src/core/core_chromium.pri b/src/core/core_chromium.pri index 5566dbef7..8ff79c782 100644 --- a/src/core/core_chromium.pri +++ b/src/core/core_chromium.pri @@ -1,10 +1,5 @@ -include($$QTWEBENGINE_OUT_ROOT/src/core/qtwebenginecore-config.pri) -QT_FOR_CONFIG += webenginecore webenginecore-private - qtConfig(debug_and_release): CONFIG += debug_and_release -include(core_common.pri) - macos { # This fixes namespace builds on macOS. Specifically namespace ambiguity issues between Qt and # Chromium forward declarations of NSString. @@ -35,7 +30,13 @@ qtConfig(webengine-embedded-build): DEFINES += QTWEBENGINE_EMBEDDED_SWITCHES INCLUDEPATH += $$PWD $$PWD/api +clang_cl { + QMAKE_CFLAGS -= $$QMAKE_CFLAGS_MSVC_COMPAT + QMAKE_CXXFLAGS -= $$QMAKE_CFLAGS_MSVC_COMPAT +} + SOURCES = \ + accessibility_activation_observer.cpp \ accessibility_tree_formatter_qt.cpp \ authentication_dialog_controller.cpp \ browser_accessibility_manager_qt.cpp \ @@ -44,21 +45,24 @@ SOURCES = \ browser_main_parts_qt.cpp \ browser_message_filter_qt.cpp \ certificate_error_controller.cpp \ - chromium_gpu_helper.cpp \ chromium_overrides.cpp \ client_cert_select_controller.cpp \ clipboard_qt.cpp \ color_chooser_qt.cpp \ color_chooser_controller.cpp \ + command_line_pref_store_qt.cpp \ common/qt_ipc_logging.cpp \ common/qt_messages.cpp \ common/user_script_data.cpp \ - compositor.cpp \ + compositor/chromium_gpu_helper.cpp \ + compositor/compositor.cpp \ + compositor/compositor_resource_tracker.cpp \ + compositor/content_gpu_client_qt.cpp \ + compositor/delegated_frame_node.cpp \ content_client_qt.cpp \ content_browser_client_qt.cpp \ content_main_delegate_qt.cpp \ content_utility_client_qt.cpp \ - delegated_frame_node.cpp \ desktop_screen_qt.cpp \ devtools_frontend_qt.cpp \ devtools_manager_delegate_qt.cpp \ @@ -70,27 +74,29 @@ SOURCES = \ login_delegate_qt.cpp \ media_capture_devices_dispatcher.cpp \ native_web_keyboard_event_qt.cpp \ + net/client_cert_override.cpp \ + net/client_cert_store_data.cpp \ net/cookie_monster_delegate_qt.cpp \ net/custom_protocol_handler.cpp \ net/network_delegate_qt.cpp \ net/proxy_config_service_qt.cpp \ - net/qrc_protocol_handler_qt.cpp \ + net/qrc_url_scheme_handler.cpp \ net/ssl_host_state_delegate_qt.cpp \ net/url_request_context_getter_qt.cpp \ net/url_request_custom_job.cpp \ net/url_request_custom_job_delegate.cpp \ net/url_request_custom_job_proxy.cpp \ - net/url_request_qrc_job_qt.cpp \ + net/url_request_notification.cpp \ net/webui_controller_factory_qt.cpp \ ozone/gl_context_qt.cpp \ ozone/gl_ozone_egl_qt.cpp \ ozone/gl_surface_qt.cpp \ ozone/gl_surface_egl_qt.cpp \ ozone/gl_surface_wgl_qt.cpp \ - ozone/ozone_platform_qt.cpp \ ozone/platform_window_qt.cpp \ ozone/surface_factory_qt.cpp \ permission_manager_qt.cpp \ + platform_notification_service_qt.cpp \ process_main.cpp \ profile_adapter.cpp \ profile_adapter_client.cpp \ @@ -100,30 +106,37 @@ SOURCES = \ quota_request_controller_impl.cpp \ register_protocol_handler_request_controller_impl.cpp \ render_view_context_menu_qt.cpp \ - render_view_observer_host_qt.cpp \ render_widget_host_view_qt.cpp \ renderer/content_renderer_client_qt.cpp \ renderer/content_settings_observer_qt.cpp \ renderer/render_frame_observer_qt.cpp \ renderer/render_view_observer_qt.cpp \ + renderer/render_thread_observer_qt.cpp \ renderer/user_resource_controller.cpp \ + renderer_host/render_view_observer_host_qt.cpp \ renderer_host/user_resource_controller_host.cpp \ resource_bundle_qt.cpp \ resource_context_qt.cpp \ service/service_qt.cpp \ + touch_handle_drawable_qt.cpp \ + touch_selection_controller_client_qt.cpp \ + touch_selection_menu_controller.cpp \ type_conversion.cpp \ + user_notification_controller.cpp \ user_script.cpp \ visited_links_manager_qt.cpp \ web_contents_adapter.cpp \ web_contents_delegate_qt.cpp \ web_contents_view_qt.cpp \ web_engine_context.cpp \ + web_engine_context_threads.cpp \ web_engine_error.cpp \ web_engine_library_info.cpp \ web_engine_settings.cpp \ web_event_factory.cpp HEADERS = \ + accessibility_activation_observer.h \ authentication_dialog_controller_p.h \ authentication_dialog_controller.h \ build_config_qt.h \ @@ -134,53 +147,60 @@ HEADERS = \ browser_message_filter_qt.h \ certificate_error_controller_p.h \ certificate_error_controller.h \ - chromium_overrides.h \ client_cert_select_controller.h \ + clipboard_change_observer.h \ clipboard_qt.h \ + command_line_pref_store_qt.h \ color_chooser_qt.h \ color_chooser_controller_p.h \ color_chooser_controller.h \ common/qt_messages.h \ common/user_script_data.h \ - compositor.h \ + compositor/chromium_gpu_helper.h \ + compositor/compositor.h \ + compositor/compositor_resource.h \ + compositor/compositor_resource_tracker.h \ + compositor/content_gpu_client_qt.h \ + compositor/delegated_frame_node.h \ content_client_qt.h \ content_browser_client_qt.h \ content_main_delegate_qt.h \ content_utility_client_qt.h \ - delegated_frame_node.h \ desktop_screen_qt.h \ devtools_frontend_qt.h \ devtools_manager_delegate_qt.h \ download_manager_delegate_qt.h \ - chromium_gpu_helper.h \ favicon_manager.h \ file_picker_controller.h \ global_descriptors_qt.h \ javascript_dialog_controller_p.h \ javascript_dialog_controller.h \ javascript_dialog_manager_qt.h \ + locked_ptr.h \ login_delegate_qt.h \ media_capture_devices_dispatcher.h \ + net/client_cert_override.h \ + net/client_cert_store_data.h \ net/cookie_monster_delegate_qt.h \ net/custom_protocol_handler.h \ net/network_delegate_qt.h \ - net/qrc_protocol_handler_qt.h \ + net/qrc_url_scheme_handler.h \ net/ssl_host_state_delegate_qt.h \ net/url_request_context_getter_qt.h \ net/url_request_custom_job.h \ net/url_request_custom_job_delegate.h \ net/url_request_custom_job_proxy.h \ - net/url_request_qrc_job_qt.h \ + net/url_request_notification.h \ net/webui_controller_factory_qt.h \ ozone/gl_context_qt.h \ ozone/gl_ozone_egl_qt.h \ ozone/gl_surface_qt.h \ ozone/gl_surface_egl_qt.h \ ozone/gl_surface_wgl_qt.h \ - ozone/ozone_platform_qt.h \ ozone/platform_window_qt.h \ ozone/surface_factory_qt.h \ permission_manager_qt.h \ + platform_notification_service_qt.h \ process_main.h \ profile_adapter.h \ profile_adapter_client.h \ @@ -193,19 +213,25 @@ HEADERS = \ register_protocol_handler_request_controller.h \ register_protocol_handler_request_controller_impl.h \ render_view_context_menu_qt.h \ - render_view_observer_host_qt.h \ render_widget_host_view_qt.h \ render_widget_host_view_qt_delegate.h \ renderer/content_renderer_client_qt.h \ renderer/content_settings_observer_qt.h \ renderer/render_frame_observer_qt.h \ renderer/render_view_observer_qt.h \ + renderer/render_thread_observer_qt.h \ renderer/user_resource_controller.h \ + renderer_host/render_view_observer_host_qt.h \ renderer_host/user_resource_controller_host.h \ request_controller.h \ resource_context_qt.h \ service/service_qt.h \ + touch_handle_drawable_client.h \ + touch_handle_drawable_qt.h \ + touch_selection_controller_client_qt.h \ + touch_selection_menu_controller.h \ type_conversion.h \ + user_notification_controller.h \ user_script.h \ visited_links_manager_qt.h \ web_contents_adapter.h \ @@ -264,12 +290,14 @@ qtConfig(webengine-printing-and-pdf) { contains(QT_CONFIG, opengl) { SOURCES += \ - yuv_video_node.cpp \ - stream_video_node.cpp + compositor/compositor_resource_fence.cpp \ + compositor/stream_video_node.cpp \ + compositor/yuv_video_node.cpp HEADERS += \ - yuv_video_node.h \ - stream_video_node.h + compositor/compositor_resource_fence.h \ + compositor/stream_video_node.h \ + compositor/yuv_video_node.h } qtConfig(webengine-geolocation) { @@ -284,3 +312,39 @@ qtConfig(webengine-webchannel) { SOURCES += renderer/web_channel_ipc_transport.cpp \ renderer_host/web_channel_ipc_transport_host.cpp } + +qtConfig(webengine-extensions) { + SOURCES += \ + common/extensions/extensions_api_provider_qt.cpp \ + common/extensions/extensions_client_qt.cpp \ + extensions/component_extension_resource_manager_qt.cpp \ + extensions/extension_system_qt.cpp \ + extensions/extension_system_factory_qt.cpp \ + extensions/extension_web_contents_observer_qt.cpp \ + extensions/extensions_api_client_qt.cpp \ + extensions/extensions_browser_api_provider_qt.cpp \ + extensions/extensions_browser_client_qt.cpp \ + extensions/mime_handler_view_guest_delegate_qt.cpp \ + renderer/extensions/extensions_dispatcher_delegate_qt.cpp \ + renderer/extensions/extensions_renderer_client_qt.cpp \ + renderer/extensions/renderer_permissions_policy_delegate_qt.cpp \ + renderer/extensions/resource_request_policy_qt.cpp \ + renderer_host/resource_dispatcher_host_delegate_qt.cpp + + HEADERS += \ + common/extensions/extensions_api_provider_qt.h \ + common/extensions/extensions_client_qt.h \ + extensions/component_extension_resource_manager_qt.h \ + extensions/extension_system_qt.h \ + extensions/extension_system_factory_qt.h \ + extensions/extension_web_contents_observer_qt.h \ + extensions/extensions_api_client_qt.h \ + extensions/extensions_browser_api_provider_qt.h \ + extensions/extensions_browser_client_qt.h \ + extensions/mime_handler_view_guest_delegate_qt.h \ + renderer/extensions/extensions_dispatcher_delegate_qt.h \ + renderer/extensions/extensions_renderer_client_qt.h \ + renderer/extensions/renderer_permissions_policy_delegate_qt.h \ + renderer/extensions/resource_request_policy_qt.h \ + renderer_host/resource_dispatcher_host_delegate_qt.h +} diff --git a/src/core/core_common.pri b/src/core/core_common.pri index 01f40eb09..c92278657 100644 --- a/src/core/core_common.pri +++ b/src/core/core_common.pri @@ -1,3 +1,6 @@ +include($$QTWEBENGINE_OUT_ROOT/src/core/qtwebenginecore-config.pri) +QT_FOR_CONFIG += webenginecore webenginecore-private + # NOTE: The TARGET, QT, QT_PRIVATE variables are used in both core_module.pro and core_gyp_generator.pro # gyp/ninja will take care of the compilation, qmake/make will finish with linking and install. @@ -13,3 +16,7 @@ CONFIG -= ltcg # Chromium requires C++14 CONFIG += c++14 + +#QTBUG-73216 ci has to be updated with latest yocto +boot2qt: CONFIG -= use_gold_linker + diff --git a/src/core/core_generator.pro b/src/core/core_generator.pro index 916c211f9..935c653a4 100644 --- a/src/core/core_generator.pro +++ b/src/core/core_generator.pro @@ -1,3 +1,5 @@ +include(core_common.pri) + include(core_gn_config.pri) TEMPLATE = lib diff --git a/src/core/core_gn_config.pri b/src/core/core_gn_config.pri index 9b0145dfc..a089eecd0 100644 --- a/src/core/core_gn_config.pri +++ b/src/core/core_gn_config.pri @@ -4,8 +4,13 @@ GN_FILE = $$OUT_PWD/$$getConfigDir()/BUILD.gn GN_FIND_MOCABLES_SCRIPT = $$shell_path($$QTWEBENGINE_ROOT/tools/scripts/gn_find_mocables.py) GN_RUN_BINARY_SCRIPT = $$shell_path($$QTWEBENGINE_ROOT/tools/scripts/gn_run_binary.py) GN_IMPORTS = $$PWD/qtwebengine.gni -GN_INCLUDES = $$PWD/qtwebengine_sources.gni $$PWD/qtwebengine_resources.gni +qtConfig (webengine-extensions) { + GN_INCLUDES += $$PWD/qtwebengine_sources.gni $$PWD/qtwebengine_resources.gni $$PWD/common/extensions/api/qtwebengine_extensions_features.gni +} else { + GN_INCLUDES = $$PWD/qtwebengine_sources.gni $$PWD/qtwebengine_resources.gni +} GN_CORE_INCLUDE_DIRS = $$PWD/service GN_CREATE_PRI = true QMAKE_INTERNAL_INCLUDED_FILES = $$GN_IMPORTS $$GN_INCLUDES $$GN_FILE + diff --git a/src/core/core_module.pro b/src/core/core_module.pro index 7bcd916a1..b220af4a5 100644 --- a/src/core/core_module.pro +++ b/src/core/core_module.pro @@ -62,12 +62,12 @@ LIBS_PRIVATE += -L$$api_library_path CONFIG *= no_smart_library_merge osx { LIBS_PRIVATE += -Wl,-force_load,$${api_library_path}$${QMAKE_DIR_SEP}lib$${api_library_name}.a -} else:msvc { +} else: win32 { !isDeveloperBuild() { # Remove unused functions and data in debug non-developer builds, because the binaries will # be smaller in the shipped packages. QMAKE_LFLAGS += /OPT:REF - } else:CONFIG(debug, debug|release) { + } else:CONFIG(debug, debug|release):!clang_cl { # Make sure to override qtbase's QMAKE_LFLAGS_DEBUG option in debug developer builds, # because qmake chooses and overrides the option when it gets appended to QMAKE_LFLAGS in # qtbase\mkspecs\features\default_post.prf, regardless of what Chromium passes back from GN. @@ -81,7 +81,7 @@ osx { QMAKE_LFLAGS += -Wl,-whole-archive -l$$api_library_name -Wl,-no-whole-archive } -win32-msvc* { +win32 { POST_TARGETDEPS += $${api_library_path}$${QMAKE_DIR_SEP}$${api_library_name}.lib } else { POST_TARGETDEPS += $${api_library_path}$${QMAKE_DIR_SEP}lib$${api_library_name}.a diff --git a/src/core/core_project.pro b/src/core/core_project.pro index ecb4a3ab5..9c8e20808 100644 --- a/src/core/core_project.pro +++ b/src/core/core_project.pro @@ -3,6 +3,7 @@ TEMPLATE = lib include(core_common.pri) + linking_pri = $$OUT_PWD/$$getConfigDir()/$${TARGET}.pri !include($$linking_pri) { diff --git a/src/core/devtools_frontend_qt.cpp b/src/core/devtools_frontend_qt.cpp index fc91fd75f..28af84bd3 100644 --- a/src/core/devtools_frontend_qt.cpp +++ b/src/core/devtools_frontend_qt.cpp @@ -48,6 +48,7 @@ #include "profile_qt.h" #include "web_contents_adapter.h" +#include "base/base64.h" #include "base/json/json_reader.h" #include "base/json/json_writer.h" #include "base/json/string_escape.h" @@ -56,11 +57,13 @@ #include "base/strings/string_number_conversions.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" +#include "base/task/post_task.h" #include "base/values.h" #include "chrome/common/url_constants.h" #include "components/prefs/in_memory_pref_store.h" #include "components/prefs/json_pref_store.h" #include "content/public/browser/browser_context.h" +#include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/navigation_controller.h" #include "content/public/browser/navigation_handle.h" @@ -71,12 +74,10 @@ #include "content/public/common/content_client.h" #include "content/public/common/url_constants.h" #include "ipc/ipc_channel.h" -#include "net/base/io_buffer.h" -#include "net/base/net_errors.h" #include "net/http/http_response_headers.h" #include "net/traffic_annotation/network_traffic_annotation.h" -#include "net/url_request/url_fetcher.h" -#include "net/url_request/url_fetcher_response_writer.h" +#include "services/network/public/cpp/simple_url_loader.h" +#include "services/network/public/cpp/simple_url_loader_stream_consumer.h" using namespace QtWebEngineCore; @@ -100,66 +101,77 @@ std::unique_ptr<base::DictionaryValue> BuildObjectForResponse(const net::HttpRes return response; } -// ResponseWriter ------------------------------------------------------------- - -class ResponseWriter : public net::URLFetcherResponseWriter { -public: - ResponseWriter(base::WeakPtr<DevToolsFrontendQt> shell_devtools_, int stream_id); - ~ResponseWriter() override; - - // URLFetcherResponseWriter overrides: - int Initialize(const net::CompletionCallback &callback) override; - int Write(net::IOBuffer *buffer, int num_bytes, const net::CompletionCallback &callback) override; - int Finish(int net_error, const net::CompletionCallback &callback) override; +static std::string GetFrontendURL() +{ + return "chrome-devtools://devtools/bundled/devtools_app.html"; +} -private: - base::WeakPtr<DevToolsFrontendQt> shell_devtools_; - int stream_id_; +} // namespace - DISALLOW_COPY_AND_ASSIGN(ResponseWriter); -}; +namespace QtWebEngineCore { -ResponseWriter::ResponseWriter(base::WeakPtr<DevToolsFrontendQt> shell_devtools, int stream_id) - : shell_devtools_(shell_devtools), stream_id_(stream_id) -{} +class DevToolsFrontendQt::NetworkResourceLoader + : public network::SimpleURLLoaderStreamConsumer { +public: + NetworkResourceLoader(int stream_id, + int request_id, + DevToolsFrontendQt *bindings, + std::unique_ptr<network::SimpleURLLoader> loader, + network::mojom::URLLoaderFactory *url_loader_factory) + : stream_id_(stream_id), + request_id_(request_id), + bindings_(bindings), + loader_(std::move(loader)) + { + loader_->SetOnResponseStartedCallback(base::BindOnce( + &NetworkResourceLoader::OnResponseStarted, base::Unretained(this))); + loader_->DownloadAsStream(url_loader_factory, this); + } -ResponseWriter::~ResponseWriter() {} +private: + void OnResponseStarted(const GURL &final_url, + const network::ResourceResponseHead &response_head) + { + response_headers_ = response_head.headers; + } -int ResponseWriter::Initialize(const net::CompletionCallback& callback) -{ - return net::OK; -} + void OnDataReceived(base::StringPiece chunk, base::OnceClosure resume) override + { + base::Value chunkValue; + + bool encoded = !base::IsStringUTF8(chunk); + if (encoded) { + std::string encoded_string; + base::Base64Encode(chunk, &encoded_string); + chunkValue = base::Value(std::move(encoded_string)); + } else { + chunkValue = base::Value(chunk); + } + base::Value id(stream_id_); + base::Value encodedValue(encoded); -int ResponseWriter::Write(net::IOBuffer *buffer, int num_bytes, const net::CompletionCallback &callback) -{ - std::string chunk = std::string(buffer->data(), num_bytes); - if (!base::IsStringUTF8(chunk)) - return num_bytes; - - base::Value *id = new base::Value(stream_id_); - base::Value *chunkValue = new base::Value(chunk); - - content::BrowserThread::PostTask( - content::BrowserThread::UI, FROM_HERE, - base::BindOnce(&DevToolsFrontendQt::CallClientFunction, - shell_devtools_, "DevToolsAPI.streamWrite", - base::Owned(id), base::Owned(chunkValue), nullptr)); - return num_bytes; -} + bindings_->CallClientFunction("DevToolsAPI.streamWrite", &id, &chunkValue, &encodedValue); + std::move(resume).Run(); + } -int ResponseWriter::Finish(int net_error, const net::CompletionCallback &callback) -{ - return net::OK; -} + void OnComplete(bool success) override + { + Q_UNUSED(success); + auto response = BuildObjectForResponse(response_headers_.get()); + bindings_->SendMessageAck(request_id_, response.get()); + bindings_->m_loaders.erase(bindings_->m_loaders.find(this)); + } -static std::string GetFrontendURL() -{ - return "chrome-devtools://devtools/bundled/devtools_app.html"; -} + void OnRetry(base::OnceClosure start_retry) override { NOTREACHED(); } -} // namespace + const int stream_id_; + const int request_id_; + DevToolsFrontendQt *const bindings_; + std::unique_ptr<network::SimpleURLLoader> loader_; + scoped_refptr<net::HttpResponseHeaders> response_headers_; -namespace QtWebEngineCore { + DISALLOW_COPY_AND_ASSIGN(NetworkResourceLoader); +}; // This constant should be in sync with // the constant at devtools_ui_bindings.cc. @@ -209,7 +221,7 @@ DevToolsFrontendQt::DevToolsFrontendQt(QSharedPointer<WebContentsAdapter> webCon // We use a separate prefstore than one in ProfileQt, because that one is in-memory only, and this // needs to be stored or it will show introduction text on every load. if (webContentsAdapter->profileAdapter()->isOffTheRecord()) - m_prefStore = std::move(scoped_refptr<PersistentPrefStore>(new InMemoryPrefStore())); + m_prefStore = scoped_refptr<PersistentPrefStore>(new InMemoryPrefStore()); else CreateJsonPreferences(false); @@ -219,8 +231,6 @@ DevToolsFrontendQt::DevToolsFrontendQt(QSharedPointer<WebContentsAdapter> webCon DevToolsFrontendQt::~DevToolsFrontendQt() { - for (const auto &pair : m_pendingRequests) - delete pair.first; } void DevToolsFrontendQt::Activate() @@ -267,9 +277,10 @@ void DevToolsFrontendQt::ReadyToCommitNavigation(content::NavigationHandle *navi if (navigationHandle->GetURL() != GetFrontendURL()) m_frontendHost.reset(nullptr); else - m_frontendHost.reset(content::DevToolsFrontendHost::Create(frame, - base::Bind(&DevToolsFrontendQt::HandleMessageFromDevToolsFrontend, - base::Unretained(this)))); + m_frontendHost = content::DevToolsFrontendHost::Create( + frame, + base::Bind(&DevToolsFrontendQt::HandleMessageFromDevToolsFrontend, + base::Unretained(this))); } } @@ -396,20 +407,29 @@ void DevToolsFrontendQt::HandleMessageFromDevToolsFrontend(const std::string &me setting: "It's not possible to disable this feature from settings." chrome_policy { - DeveloperToolsDisabled { + DeveloperToolsAvailability { policy_options {mode: MANDATORY} - DeveloperToolsDisabled: true + DeveloperToolsAvailability: 2 } } })"); - net::URLFetcher *fetcher = net::URLFetcher::Create(gurl, net::URLFetcher::GET, this, traffic_annotation).release(); - m_pendingRequests[fetcher] = request_id; - fetcher->SetRequestContext(content::BrowserContext::GetDefaultStoragePartition( - web_contents()->GetBrowserContext())->GetURLRequestContext()); - fetcher->SetExtraRequestHeaders(headers); - fetcher->SaveResponseWithWriter(std::unique_ptr<net::URLFetcherResponseWriter>( - new ResponseWriter(m_weakFactory.GetWeakPtr(), stream_id))); - fetcher->Start(); + auto resource_request = std::make_unique<network::ResourceRequest>(); + resource_request->url = gurl; + // TODO(caseq): this preserves behavior of URLFetcher-based implementation. + // We really need to pass proper first party origin from the front-end. + resource_request->site_for_cookies = gurl; + resource_request->headers.AddHeadersFromString(headers); + + auto *partition = content::BrowserContext::GetStoragePartitionForSite( + web_contents()->GetBrowserContext(), gurl); + auto factory = partition->GetURLLoaderFactoryForBrowserProcess(); + + auto simple_url_loader = network::SimpleURLLoader::Create( + std::move(resource_request), traffic_annotation); + auto resource_loader = std::make_unique<NetworkResourceLoader>( + stream_id, request_id, this, std::move(simple_url_loader), + factory.get()); + m_loaders.insert(std::move(resource_loader)); return; } else if (method == "getPreferences") { m_preferences = std::move(*m_prefStore->GetValues()); @@ -489,21 +509,6 @@ void DevToolsFrontendQt::DispatchProtocolMessage(content::DevToolsAgentHost *age } } -void DevToolsFrontendQt::OnURLFetchComplete(const net::URLFetcher *source) -{ - // TODO(pfeldman): this is a copy of chrome's devtools_ui_bindings.cc. - // We should handle some of the commands including this one in content. - DCHECK(source); - PendingRequestsMap::iterator it = m_pendingRequests.find(source); - DCHECK(it != m_pendingRequests.end()); - - auto response = BuildObjectForResponse(source->GetResponseHeaders()); - - SendMessageAck(it->second, response.get()); - m_pendingRequests.erase(it); - delete source; -} - void DevToolsFrontendQt::CallClientFunction(const std::string &function_name, const base::Value *arg1, const base::Value *arg2, diff --git a/src/core/devtools_frontend_qt.h b/src/core/devtools_frontend_qt.h index 88cc7aeac..fed2d47fc 100644 --- a/src/core/devtools_frontend_qt.h +++ b/src/core/devtools_frontend_qt.h @@ -41,10 +41,12 @@ #define DEVTOOLS_FRONTEND_QT_H #include <memory> +#include <set> #include "web_contents_delegate_qt.h" #include "base/compiler_specific.h" +#include "base/containers/unique_ptr_adapters.h" #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" @@ -52,7 +54,6 @@ #include "content/public/browser/devtools_agent_host.h" #include "content/public/browser/devtools_frontend_host.h" #include "content/public/browser/web_contents_observer.h" -#include "net/url_request/url_fetcher_delegate.h" namespace base { class Value; @@ -69,8 +70,7 @@ class PersistentPrefStore; namespace QtWebEngineCore { class DevToolsFrontendQt : public content::WebContentsObserver - , public content::DevToolsAgentHostClient - , public net::URLFetcherDelegate { + , public content::DevToolsAgentHostClient { public: static DevToolsFrontendQt *Show(QSharedPointer<WebContentsAdapter> frontendAdapter, content::WebContents *inspectedContents); @@ -108,9 +108,6 @@ private: void DocumentAvailableInMainFrame() override; void WebContentsDestroyed() override; - // net::URLFetcherDelegate overrides. - void OnURLFetchComplete(const net::URLFetcher* source) override; - void SendMessageAck(int request_id, const base::Value* arg1); void SetPreference(const std::string &name, const std::string &value); void RemovePreference(const std::string &name); @@ -125,8 +122,10 @@ private: int m_inspect_element_at_x; int m_inspect_element_at_y; std::unique_ptr<content::DevToolsFrontendHost> m_frontendHost; - using PendingRequestsMap = std::map<const net::URLFetcher*, int>; - PendingRequestsMap m_pendingRequests; + + class NetworkResourceLoader; + std::set<std::unique_ptr<NetworkResourceLoader>, base::UniquePtrComparator> m_loaders; + base::DictionaryValue m_preferences; scoped_refptr<PersistentPrefStore> m_prefStore; base::WeakPtrFactory<DevToolsFrontendQt> m_weakFactory; diff --git a/src/core/download_manager_delegate_qt.cpp b/src/core/download_manager_delegate_qt.cpp index f39830ff2..2af958068 100644 --- a/src/core/download_manager_delegate_qt.cpp +++ b/src/core/download_manager_delegate_qt.cpp @@ -112,7 +112,7 @@ void DownloadManagerDelegateQt::pauseDownload(quint32 downloadId) void DownloadManagerDelegateQt::resumeDownload(quint32 downloadId) { if (download::DownloadItem *download = findDownloadById(downloadId)) - download->Resume(); + download->Resume(/* user_resume */ true); } void DownloadManagerDelegateQt::removeDownload(quint32 downloadId) @@ -166,7 +166,7 @@ bool DownloadManagerDelegateQt::DetermineDownloadTarget(download::DownloadItem* suggestedFilename += QStringLiteral(".") + mimeType.preferredSuffix(); } - QDir defaultDownloadDirectory = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation); + QDir defaultDownloadDirectory(m_profileAdapter->downloadPath()); QFileInfo suggestedFile(defaultDownloadDirectory.absoluteFilePath(suggestedFilename)); QString suggestedFilePath = suggestedFile.absoluteFilePath(); diff --git a/src/core/download_manager_delegate_qt.h b/src/core/download_manager_delegate_qt.h index db965b12d..382c57524 100644 --- a/src/core/download_manager_delegate_qt.h +++ b/src/core/download_manager_delegate_qt.h @@ -104,7 +104,7 @@ private: void savePackageDownloadCreated(download::DownloadItem *download); ProfileAdapter *m_profileAdapter; - uint64_t m_currentId; + uint32_t m_currentId; base::WeakPtrFactory<DownloadManagerDelegateQt> m_weakPtrFactory; bool m_nextDownloadIsUserRequested; diff --git a/src/core/extensions/component_extension_resource_manager_qt.cpp b/src/core/extensions/component_extension_resource_manager_qt.cpp new file mode 100644 index 000000000..57e35c231 --- /dev/null +++ b/src/core/extensions/component_extension_resource_manager_qt.cpp @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// based on chrome/browser/extensions/chrome_component_extension_resource_manager.cc: +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "component_extension_resource_manager_qt.h" + +#include "base/logging.h" +#include "base/path_service.h" +#include "chrome/grit/component_extension_resources_map.h" + +namespace extensions { + +ComponentExtensionResourceManagerQt::ComponentExtensionResourceManagerQt() +{ + AddComponentResourceEntries(kComponentExtensionResources, + kComponentExtensionResourcesSize); +} + +ComponentExtensionResourceManagerQt::~ComponentExtensionResourceManagerQt() {} + +bool ComponentExtensionResourceManagerQt::IsComponentExtensionResource(const base::FilePath &extension_path, + const base::FilePath &resource_path, + int *resource_id) const +{ + base::FilePath directory_path = extension_path; + base::FilePath resources_dir; + base::FilePath relative_path; + if (!base::PathService::Get(base::DIR_QT_LIBRARY_DATA, &resources_dir) + || !resources_dir.AppendRelativePath(directory_path, &relative_path)) { + return false; + } + + relative_path = relative_path.Append(resource_path); + relative_path = relative_path.NormalizePathSeparators(); + + std::map<base::FilePath, int>::const_iterator entry = path_to_resource_id_.find(relative_path); + if (entry != path_to_resource_id_.end()) + *resource_id = entry->second; + + return entry != path_to_resource_id_.end(); +} + +const ui::TemplateReplacements *ComponentExtensionResourceManagerQt::GetTemplateReplacementsForExtension(const std::string &) const +{ + return nullptr; +} + +void ComponentExtensionResourceManagerQt::AddComponentResourceEntries(const GritResourceMap *entries, size_t size) +{ + for (size_t i = 0; i < size; ++i) { + base::FilePath resource_path = base::FilePath().AppendASCII(entries[i].name); + resource_path = resource_path.NormalizePathSeparators(); + + DCHECK(path_to_resource_id_.find(resource_path) == path_to_resource_id_.end()); + path_to_resource_id_[resource_path] = entries[i].value; + } +} + +} // namespace extensions diff --git a/src/core/extensions/component_extension_resource_manager_qt.h b/src/core/extensions/component_extension_resource_manager_qt.h new file mode 100644 index 000000000..2d858630f --- /dev/null +++ b/src/core/extensions/component_extension_resource_manager_qt.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENT_EXTENSION_RESOURCE_MANAGER_QT_H_ +#define COMPONENT_EXTENSION_RESOURCE_MANAGER_QT_H_ + +#include <map> + +#include "base/files/file_path.h" +#include "extensions/browser/component_extension_resource_manager.h" + +struct GritResourceMap; + +namespace extensions { + +class ComponentExtensionResourceManagerQt : public ComponentExtensionResourceManager +{ +public: + ComponentExtensionResourceManagerQt(); + ~ComponentExtensionResourceManagerQt() override; + + // Overridden from ComponentExtensionResourceManager: + bool IsComponentExtensionResource(const base::FilePath &extension_path, + const base::FilePath &resource_path, + int *resource_id) const override; + const ui::TemplateReplacements *GetTemplateReplacementsForExtension(const std::string& extension_id) const override; + +private: + void AddComponentResourceEntries(const GritResourceMap* entries, size_t size); + + // A map from a resource path to the resource ID. Used by + // IsComponentExtensionResource. + std::map<base::FilePath, int> path_to_resource_id_; + + DISALLOW_COPY_AND_ASSIGN(ComponentExtensionResourceManagerQt); +}; + +} // namespace extensions + +#endif // COMPONENT_EXTENSION_RESOURCE_MANAGER_QT_H_ diff --git a/src/core/extensions/extension_system_factory_qt.cpp b/src/core/extensions/extension_system_factory_qt.cpp new file mode 100644 index 000000000..41ba31214 --- /dev/null +++ b/src/core/extensions/extension_system_factory_qt.cpp @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "extension_system_factory_qt.h" + +#include "components/keyed_service/content/browser_context_dependency_manager.h" +#include "extensions/browser/declarative_user_script_manager_factory.h" +#include "extensions/browser/event_router_factory.h" +#include "extensions/browser/extension_prefs_factory.h" +#include "extensions/browser/extension_registry_factory.h" +#include "extensions/browser/extension_system.h" +#include "extensions/browser/extensions_browser_client.h" +#include "extensions/browser/process_manager_factory.h" +#include "extensions/browser/renderer_startup_helper.h" + +namespace extensions { + +// static +ExtensionSystem *ExtensionSystemFactoryQt::GetForBrowserContext(content::BrowserContext *context) +{ + return static_cast<ExtensionSystem *>(GetInstance()->GetServiceForBrowserContext(context, true)); +} + +// static +ExtensionSystemFactoryQt *ExtensionSystemFactoryQt::GetInstance() +{ + return base::Singleton<ExtensionSystemFactoryQt>::get(); +} + +ExtensionSystemFactoryQt::ExtensionSystemFactoryQt() + : ExtensionSystemProvider("ExtensionSystem", BrowserContextDependencyManager::GetInstance()) +{ + DCHECK(ExtensionsBrowserClient::Get()) << "ExtensionSystemFactory must be initialized after BrowserProcess"; + DependsOn(ExtensionPrefsFactory::GetInstance()); + DependsOn(ExtensionRegistryFactory::GetInstance()); +} + +ExtensionSystemFactoryQt::~ExtensionSystemFactoryQt() +{ +} + +KeyedService *ExtensionSystemFactoryQt::BuildServiceInstanceFor(content::BrowserContext *context) const +{ + return new ExtensionSystemQt(context); +} + +content::BrowserContext *ExtensionSystemFactoryQt::GetBrowserContextToUse(content::BrowserContext *context) const +{ + // Separate instance in incognito. + return context; +} + +bool ExtensionSystemFactoryQt::ServiceIsCreatedWithBrowserContext() const +{ + return true; +} + +} // namespace extensions diff --git a/src/core/extensions/extension_system_factory_qt.h b/src/core/extensions/extension_system_factory_qt.h new file mode 100644 index 000000000..6e840b6d6 --- /dev/null +++ b/src/core/extensions/extension_system_factory_qt.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef EXTENSION_SYSTEM_FACTORY_QT_H_ +#define EXTENSION_SYSTEM_FACTORY_QT_H_ + +#include "base/macros.h" +#include "base/memory/singleton.h" +#include "components/keyed_service/content/browser_context_keyed_service_factory.h" +#include "extensions/browser/extension_system_provider.h" +#include "extension_system_qt.h" + +namespace extensions { +class ExtensionSystem; + +// BrowserContextKeyedServiceFactory for ExtensionSystemImpl. +// TODO(yoz): Rename to ExtensionSystemImplFactory. +class ExtensionSystemFactoryQt : public ExtensionSystemProvider +{ +public: + // ExtensionSystem provider implementation: + ExtensionSystem *GetForBrowserContext(content::BrowserContext *context) override; + + static ExtensionSystemFactoryQt *GetInstance(); + +private: + friend struct base::DefaultSingletonTraits<ExtensionSystemFactoryQt>; + + ExtensionSystemFactoryQt(); + ~ExtensionSystemFactoryQt() override; + + // BrowserContextKeyedServiceFactory implementation: + KeyedService *BuildServiceInstanceFor(content::BrowserContext *context) const override; + content::BrowserContext *GetBrowserContextToUse(content::BrowserContext *context) const override; + bool ServiceIsCreatedWithBrowserContext() const override; + + DISALLOW_COPY_AND_ASSIGN(ExtensionSystemFactoryQt); +}; + +} // namespace extensions + +#endif // EXTENSION_SYSTEM_FACTORY_QT_H_ diff --git a/src/core/extensions/extension_system_qt.cpp b/src/core/extensions/extension_system_qt.cpp new file mode 100644 index 000000000..4ca407421 --- /dev/null +++ b/src/core/extensions/extension_system_qt.cpp @@ -0,0 +1,447 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "extension_system_qt.h" + +#include <algorithm> + +#include "base/base_paths.h" +#include "base/base_switches.h" +#include "base/bind.h" +#include "base/command_line.h" +#include "base/files/file_path.h" +#include "base/files/file_util.h" +#include "base/json/json_string_value_serializer.h" +#include "base/memory/ptr_util.h" +#include "base/memory/weak_ptr.h" +#include "base/path_service.h" +#include "base/strings/string_tokenizer.h" +#include "base/strings/utf_string_conversions.h" +#include "base/task/post_task.h" +#include "base/time/time.h" +#include "base/trace_event/trace_event.h" +#include "build/build_config.h" +#include "components/crx_file/id_util.h" +#include "content/public/browser/browser_context.h" +#include "content/public/browser/browser_task_traits.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/notification_service.h" +#include "content/public/browser/plugin_service.h" +#include "content/public/browser/render_process_host.h" +#include "content/public/browser/url_data_source.h" +#include "content/public/common/webplugininfo.h" +#include "extensions/browser/content_verifier.h" +#include "extensions/browser/content_verifier_delegate.h" +#include "extensions/browser/extension_pref_store.h" +#include "extensions/browser/extension_pref_value_map.h" +#include "extensions/browser/extension_pref_value_map_factory.h" +#include "extensions/browser/extension_prefs.h" +#include "extensions/browser/extension_registry.h" +#include "extensions/browser/info_map.h" +#include "extensions/browser/notification_types.h" +#include "extensions/browser/null_app_sorting.h" +#include "extensions/browser/quota_service.h" +#include "extensions/browser/renderer_startup_helper.h" +#include "extensions/browser/runtime_data.h" +#include "extensions/browser/shared_user_script_master.h" +#include "extensions/browser/service_worker_manager.h" +#include "extensions/browser/value_store/value_store_factory_impl.h" +#include "extensions/common/constants.h" +#include "extensions/common/extension_messages.h" +#include "extensions/common/manifest_constants.h" +#include "extensions/common/manifest_handlers/mime_types_handler.h" +#include "extensions/common/manifest_url_handlers.h" +#include "ui/base/resource/resource_bundle.h" +#include "chrome/grit/component_extension_resources.h" +#include "chrome/grit/browser_resources.h" +#include "net/base/mime_util.h" + +using content::BrowserThread; + +namespace extensions { + +namespace { + +std::string GenerateId(const base::DictionaryValue *manifest, + const base::FilePath &path) +{ + std::string raw_key; + std::string id_input; + CHECK(manifest->GetString(manifest_keys::kPublicKey, &raw_key)); + CHECK(Extension::ParsePEMKeyBytes(raw_key, &id_input)); + std::string id = crx_file::id_util::GenerateId(id_input); + return id; +} + +// Implementation based on ComponentLoader::ParseManifest. +std::unique_ptr<base::DictionaryValue> ParseManifest(const std::string &manifest_contents) +{ + JSONStringValueDeserializer deserializer(manifest_contents); + std::unique_ptr<base::Value> manifest(deserializer.Deserialize(NULL, NULL)); + + if (!manifest.get() || !manifest->is_dict()) { + LOG(ERROR) << "Failed to parse extension manifest."; + return NULL; + } + // Transfer ownership to the caller. + return base::DictionaryValue::From(std::move(manifest)); +} + +} // namespace + +// Dummy Content Verifier Delegate. Added to prevent crashes. +class ContentVerifierDelegateQt + : public ContentVerifierDelegate { + public: + ~ContentVerifierDelegateQt() override {} + + // This should return what verification mode is appropriate for the given + // extension, if any. + Mode ShouldBeVerified(const Extension& extension) override { + return NONE; + } + + // Should return the public key to use for validating signatures via the two + // out parameters. + ContentVerifierKey GetPublicKey() override { + return ContentVerifierKey(); + } + // This should return a URL that can be used to fetch the + // verified_contents.json containing signatures for the given extension + // id/version pair. + GURL GetSignatureFetchUrl(const std::string& extension_id, + const base::Version& version) override { + return GURL(); + } + + // This should return the set of file paths for images used within the + // browser process. (These may get transcoded during the install process). + std::set<base::FilePath> GetBrowserImagePaths( + const extensions::Extension* extension) override { + return std::set<base::FilePath>(); + } + + // Called when the content verifier detects that a read of a file inside + // an extension did not match its expected hash. + void VerifyFailed(const std::string& extension_id, + ContentVerifyJob::FailureReason reason) override { + + } + + // Called when ExtensionSystem is shutting down. + void Shutdown() override { + + } +}; + +void ExtensionSystemQt::LoadExtension(std::string extension_id, std::unique_ptr<base::DictionaryValue> manifest, const base::FilePath &directory) +{ + int flags = Extension::REQUIRE_KEY; + std::string error; + scoped_refptr<const Extension> extension = Extension::Create( + directory, + Manifest::COMPONENT, + *manifest, + flags, + &error); + if (!extension.get()) + LOG(ERROR) << error; + + base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::IO}, + base::Bind(&InfoMap::AddExtension, + base::Unretained(info_map()), + base::RetainedRef(extension), + base::Time::Now(), + true, + false)); + extension_registry_->AddEnabled(extension.get()); + + NotifyExtensionLoaded(extension.get()); +} + +void ExtensionSystemQt::OnExtensionRegisteredWithRequestContexts(scoped_refptr<const extensions::Extension> extension) +{ + extension_registry_->AddReady(extension); + if (extension_registry_->enabled_extensions().Contains(extension->id())) + extension_registry_->TriggerOnReady(extension.get()); +} + +// Implementation based on ExtensionService::NotifyExtensionLoaded. +void ExtensionSystemQt::NotifyExtensionLoaded(const Extension *extension) +{ + // The URLRequestContexts need to be first to know that the extension + // was loaded, otherwise a race can arise where a renderer that is created + // for the extension may try to load an extension URL with an extension id + // that the request context doesn't yet know about. The profile is responsible + // for ensuring its URLRequestContexts appropriately discover the loaded + // extension. + RegisterExtensionWithRequestContexts( + extension, + base::Bind(&ExtensionSystemQt::OnExtensionRegisteredWithRequestContexts, + weak_ptr_factory_.GetWeakPtr(), + base::WrapRefCounted(extension))); + + // Tell renderers about the loaded extension. + renderer_helper_->OnExtensionLoaded(*extension); + + // Tell subsystems that use the ExtensionRegistryObserver::OnExtensionLoaded + // about the new extension. + // + // NOTE: It is important that this happen after notifying the renderers about + // the new extensions so that if we navigate to an extension URL in + // ExtensionRegistryObserver::OnExtensionLoaded the renderer is guaranteed to + // know about it. + extension_registry_->TriggerOnLoaded(extension); + + // Register plugins included with the extension. + // Implementation based on PluginManager::OnExtensionLoaded. + const MimeTypesHandler *handler = MimeTypesHandler::GetHandler(extension); + if (handler && !handler->handler_url().empty()) { + content::WebPluginInfo info; + info.type = content::WebPluginInfo::PLUGIN_TYPE_BROWSER_PLUGIN; + info.name = base::UTF8ToUTF16(extension->name()); + info.path = base::FilePath::FromUTF8Unsafe(extension->url().spec()); + for (std::set<std::string>::const_iterator mime_type = handler->mime_type_set().begin(); + mime_type != handler->mime_type_set().end(); ++mime_type) { + content::WebPluginMimeType mime_type_info; + mime_type_info.mime_type = *mime_type; + base::FilePath::StringType file_extension; + if (net::GetPreferredExtensionForMimeType(*mime_type, &file_extension)) { + mime_type_info.file_extensions.push_back( + base::FilePath(file_extension).AsUTF8Unsafe()); + } + info.mime_types.push_back(mime_type_info); + } + content::PluginService *plugin_service = + content::PluginService::GetInstance(); + plugin_service->RefreshPlugins(); + plugin_service->RegisterInternalPlugin(info, true); + } +} + +bool ExtensionSystemQt::FinishDelayedInstallationIfReady(const std::string &extension_id, bool install_immediately) +{ + // TODO mibrunin + return false; +} + +void ExtensionSystemQt::Shutdown() +{ + if (content_verifier_.get()) + content_verifier_->Shutdown(); +} + +ServiceWorkerManager *ExtensionSystemQt::service_worker_manager() +{ + return service_worker_manager_.get(); +} + +ExtensionService *ExtensionSystemQt::extension_service() +{ + return nullptr; +} + +RuntimeData *ExtensionSystemQt::runtime_data() +{ + return runtime_data_.get(); +} + +ManagementPolicy *ExtensionSystemQt::management_policy() +{ + return nullptr; +} + +SharedUserScriptMaster *ExtensionSystemQt::shared_user_script_master() +{ + return shared_user_script_master_.get(); +} + +StateStore *ExtensionSystemQt::state_store() +{ + return nullptr; +} + +StateStore *ExtensionSystemQt::rules_store() +{ + return nullptr; +} + +scoped_refptr<ValueStoreFactory> ExtensionSystemQt::store_factory() +{ + return store_factory_; +} + +InfoMap *ExtensionSystemQt::info_map() +{ + if (!info_map_.get()) + info_map_ = new InfoMap; + return info_map_.get(); +} + +QuotaService *ExtensionSystemQt::quota_service() +{ + return quota_service_.get(); +} + +AppSorting *ExtensionSystemQt::app_sorting() +{ + return app_sorting_.get(); +} + +ContentVerifier *ExtensionSystemQt::content_verifier() +{ + if (!content_verifier_.get()) { + content_verifier_ = new ContentVerifier(browser_context_, std::make_unique<ContentVerifierDelegateQt>()); + } + return content_verifier_.get(); +} + +ExtensionSystemQt::ExtensionSystemQt(content::BrowserContext *browserContext) + : browser_context_(browserContext) + , store_factory_(new ValueStoreFactoryImpl(browserContext->GetPath())) + , extension_registry_(ExtensionRegistry::Get(browserContext)) + , renderer_helper_(extensions::RendererStartupHelperFactory::GetForBrowserContext(browserContext)) + , initialized_(false) + , weak_ptr_factory_(this) +{ +} + +ExtensionSystemQt::~ExtensionSystemQt() +{ +} + +void ExtensionSystemQt::Init(bool extensions_enabled) +{ + if (initialized_) + return; + + initialized_ = true; + + service_worker_manager_.reset(new ServiceWorkerManager(browser_context_)); + runtime_data_.reset(new RuntimeData(extension_registry_)); + quota_service_.reset(new QuotaService); + app_sorting_.reset(new NullAppSorting); + + shared_user_script_master_ = + std::make_unique<SharedUserScriptMaster>(browser_context_); + + // Make the chrome://extension-icon/ resource available. + // content::URLDataSource::Add(browser_context_, new ExtensionIconSource(browser_context_)); + + if (extensions_enabled) { + // Inform the rest of the extensions system to start. + ready_.Signal(); + content::NotificationService::current()->Notify( + NOTIFICATION_EXTENSIONS_READY_DEPRECATED, + content::Source<content::BrowserContext>(browser_context_), + content::NotificationService::NoDetails()); + + std::string pdf_manifest = ui::ResourceBundle::GetSharedInstance().GetRawDataResource(IDR_PDF_MANIFEST).as_string(); + base::ReplaceFirstSubstringAfterOffset(&pdf_manifest, 0, "<NAME>", "chromium-pdf"); + + std::unique_ptr<base::DictionaryValue> pdfManifestDict = ParseManifest(pdf_manifest); + base::FilePath path; + base::PathService::Get(base::DIR_QT_LIBRARY_DATA, &path); + path = path.Append(base::FilePath(FILE_PATH_LITERAL("pdf"))); + std::string id = GenerateId(pdfManifestDict.get(), path); + LoadExtension(id, std::move(pdfManifestDict), path); + } +} + +void ExtensionSystemQt::InitForRegularProfile(bool extensions_enabled) +{ + if (initialized_) + return; // Already initialized. + // The InfoMap needs to be created before the ProcessManager. + info_map(); + + Init(extensions_enabled); +} + +void ExtensionSystemQt::InitForIncognitoProfile() +{ + NOTIMPLEMENTED(); +} + +std::unique_ptr<ExtensionSet> ExtensionSystemQt::GetDependentExtensions(const Extension *extension) +{ + return base::WrapUnique(new ExtensionSet()); +} + +#if !defined(TOOLKIT_QT) +void ExtensionSystemQt::InstallUpdate(const std::string &extension_id, + const std::string &public_key, + const base::FilePath &unpacked_dir, + bool install_immediately, + InstallUpdateCallback install_update_callback) +{ + NOTREACHED() << "Not yet implemented"; + base::DeleteFile(unpacked_dir, true /* recursive */); + std::move(install_update_callback).Run(CrxInstallError(CrxInstallErrorType::DECLINED, CrxInstallErrorDetail::DISALLOWED_BY_POLICY)); +} +#endif + +void ExtensionSystemQt::RegisterExtensionWithRequestContexts(const Extension *extension, + const base::Closure &callback) +{ + base::Time install_time = base::Time::Now(); + + bool incognito_enabled = false; + bool notifications_disabled = false; + + base::PostTaskWithTraitsAndReply( + FROM_HERE, {BrowserThread::IO}, + base::Bind(&InfoMap::AddExtension, info_map(), + base::RetainedRef(extension), install_time, incognito_enabled, + notifications_disabled), + callback); +} + +void ExtensionSystemQt::UnregisterExtensionWithRequestContexts(const std::string &extension_id, + const UnloadedExtensionReason reason) +{ + base::PostTaskWithTraits( + FROM_HERE, {BrowserThread::IO}, + base::Bind(&InfoMap::RemoveExtension, info_map(), extension_id, reason)); +} +} // namespace extensions diff --git a/src/core/extensions/extension_system_qt.h b/src/core/extensions/extension_system_qt.h new file mode 100644 index 000000000..0ebe1d044 --- /dev/null +++ b/src/core/extensions/extension_system_qt.h @@ -0,0 +1,158 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Large parts of this file are based on the source code from the file +// chrome/browser/extensions/extension_system_impl.h from the Chromium sources. + +#ifndef EXTENSION_SYSTEM_QT_H +#define EXTENSION_SYSTEM_QT_H + +#include <string> + +#include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "build/build_config.h" +#include "extensions/browser/extension_system.h" +#include "extensions/common/extension_set.h" +#include "extensions/common/one_shot_event.h" + +namespace extensions { + +class ExtensionRegistry; +class InfoMap; +class RendererStartupHelper; +class ServiceWorkerManager; +class StateStoreNotificationObserver; +class ValueStoreFactory; +class ValueStoreFactoryImpl; + +// The ExtensionSystem for ProfileImpl and OffTheRecordProfileImpl. +// Implementation details: non-shared services are owned by +// ExtensionSystemImpl, a KeyedService with separate incognito +// instances. A private Shared class (also a KeyedService, +// but with a shared instance for incognito) keeps the common services. +class ExtensionSystemQt : public ExtensionSystem +{ +public: + explicit ExtensionSystemQt(content::BrowserContext *browserContext); + ~ExtensionSystemQt() override; + + // Initializes the extension system. + void Initialize(); + + // KeyedService implementation: + void Shutdown() override; + + // ExtensionSystem implementation: + void InitForRegularProfile(bool extensions_enabled) override; + void InitForIncognitoProfile() override; + ExtensionService *extension_service() override; + RuntimeData *runtime_data() override; + ManagementPolicy *management_policy() override; + ServiceWorkerManager *service_worker_manager() override; + SharedUserScriptMaster *shared_user_script_master() override; + StateStore* state_store() override; + StateStore* rules_store() override; + scoped_refptr<ValueStoreFactory> store_factory() override; + InfoMap *info_map() override; + QuotaService *quota_service() override; + AppSorting *app_sorting() override; + + void RegisterExtensionWithRequestContexts(const Extension *extension, + const base::Closure &callback) override; + + void UnregisterExtensionWithRequestContexts(const std::string &extension_id, + const UnloadedExtensionReason reason) override; + + ContentVerifier *content_verifier() override; + std::unique_ptr<ExtensionSet> GetDependentExtensions(const Extension *extension) override; + +#if !defined(TOOLKIT_QT) + void InstallUpdate(const std::string &extension_id, + const std::string &public_key, + const base::FilePath &unpacked_dir, + bool install_immediately, + InstallUpdateCallback install_update_callback) override; +#endif // TOOLKIT_QT + //friend class ExtensionSystemSharedFactory; + + bool FinishDelayedInstallationIfReady(const std::string &extension_id, bool install_immediately) override; + + void Init(bool extensions_enabled); + + const OneShotEvent &ready() const override { return ready_; } + +private: + void OnExtensionRegisteredWithRequestContexts(scoped_refptr<const extensions::Extension> extension); + + void NotifyExtensionLoaded(const Extension *extension); + void LoadExtension(std::string extension_id, std::unique_ptr<base::DictionaryValue> manifest, const base::FilePath &directory); + // The services that are shared between normal and incognito profiles. + + // Data to be accessed on the IO thread. Must outlive process_manager_. + scoped_refptr<InfoMap> info_map_; + + std::unique_ptr<ServiceWorkerManager> service_worker_manager_; + std::unique_ptr<RuntimeData> runtime_data_; + std::unique_ptr<QuotaService> quota_service_; + std::unique_ptr<AppSorting> app_sorting_; + std::unique_ptr<SharedUserScriptMaster> shared_user_script_master_; + + + // For verifying the contents of extensions read from disk. + scoped_refptr<ContentVerifier> content_verifier_; + OneShotEvent ready_; + + content::BrowserContext *browser_context_; + scoped_refptr<ValueStoreFactory> store_factory_; + ExtensionRegistry *extension_registry_; + extensions::RendererStartupHelper *renderer_helper_; + bool initialized_; + + base::WeakPtrFactory<ExtensionSystemQt> weak_ptr_factory_; + DISALLOW_COPY_AND_ASSIGN(ExtensionSystemQt); +}; + +} // namespace extensions + +#endif // EXTENSION_SYSTEM_QT_H diff --git a/src/core/extensions/extension_web_contents_observer_qt.cpp b/src/core/extensions/extension_web_contents_observer_qt.cpp new file mode 100644 index 000000000..365f04e46 --- /dev/null +++ b/src/core/extensions/extension_web_contents_observer_qt.cpp @@ -0,0 +1,126 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "extension_web_contents_observer_qt.h" + +#include "content/public/browser/child_process_security_policy.h" +#include "content/public/browser/render_process_host.h" +#include "content/public/browser/render_frame_host.h" +#include "content/public/common/url_constants.h" +#include "extensions/browser/extension_registry.h" +#include "extensions/common/manifest.h" + +namespace extensions { + +ExtensionWebContentsObserverQt::ExtensionWebContentsObserverQt(content::WebContents *web_contents) + : ExtensionWebContentsObserver(web_contents) +{ +} + +ExtensionWebContentsObserverQt::~ExtensionWebContentsObserverQt() +{ +} + +// static +void ExtensionWebContentsObserverQt::CreateForWebContents(content::WebContents *web_contents) +{ + content::WebContentsUserData<ExtensionWebContentsObserverQt>::CreateForWebContents(web_contents); + + // Initialize this instance if necessary. + FromWebContents(web_contents)->Initialize(); +} + +std::string ExtensionWebContentsObserverQt::GetExtensionIdFromFrame(content::RenderFrameHost *render_frame_host) const +{ + const GURL &site = render_frame_host->GetSiteInstance()->GetSiteURL(); + if (!site.SchemeIs(kExtensionScheme)) + return std::string(); + + return site.host(); +} + +const Extension *ExtensionWebContentsObserverQt::GetExtensionFromFrame(content::RenderFrameHost *render_frame_host, bool verify_url) const +{ + std::string extension_id = GetExtensionIdFromFrame(render_frame_host); + if (extension_id.empty()) + return nullptr; + + content::BrowserContext *browser_context = + render_frame_host->GetProcess()->GetBrowserContext(); + const Extension *extension = ExtensionRegistry::Get(browser_context) + ->enabled_extensions() + .GetByID(extension_id); + if (!extension) + return nullptr; + + if (verify_url) { + const url::Origin &origin(render_frame_host->GetLastCommittedOrigin()); + // Without site isolation, this check is needed to eliminate non-extension + // schemes. With site isolation, this is still needed to exclude sandboxed + // extension frames with a unique origin. + const GURL site_url(render_frame_host->GetSiteInstance()->GetSiteURL()); + if (origin.opaque() || site_url != content::SiteInstance::GetSiteForURL(browser_context, origin.GetURL())) + return nullptr; + } + + return extension; +} + +void ExtensionWebContentsObserverQt::RenderFrameCreated(content::RenderFrameHost *render_frame_host) +{ + ExtensionWebContentsObserver::RenderFrameCreated(render_frame_host); + + const Extension *extension = GetExtensionFromFrame(render_frame_host, false); + if (!extension) + return; + + int process_id = render_frame_host->GetProcess()->GetID(); + auto *policy = content::ChildProcessSecurityPolicy::GetInstance(); + + if (extension->is_extension() && Manifest::IsComponentLocation(extension->location())) + policy->GrantRequestOrigin(process_id, url::Origin::Create(GURL(content::kChromeUIResourcesURL))); +} + +WEB_CONTENTS_USER_DATA_KEY_IMPL(ExtensionWebContentsObserverQt) + +} // namespace extensions diff --git a/src/core/extensions/extension_web_contents_observer_qt.h b/src/core/extensions/extension_web_contents_observer_qt.h new file mode 100644 index 000000000..267a1095c --- /dev/null +++ b/src/core/extensions/extension_web_contents_observer_qt.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef EXTENSION_WEB_CONTENTS_OBSERVER_QT_H_ +#define EXTENSION_WEB_CONTENTS_OBSERVER_QT_H_ + +#include "content/public/browser/web_contents_user_data.h" +#include "extensions/browser/extension_web_contents_observer.h" + +namespace extensions { + +class ExtensionWebContentsObserverQt + : public ExtensionWebContentsObserver, + public content::WebContentsUserData<ExtensionWebContentsObserverQt> +{ +public: + explicit ExtensionWebContentsObserverQt(content::WebContents *web_contents); + ~ExtensionWebContentsObserverQt() override; + + static void CreateForWebContents(content::WebContents *web_contents); + + std::string GetExtensionIdFromFrame(content::RenderFrameHost *) const; + const Extension *GetExtensionFromFrame(content::RenderFrameHost *, bool) const; + + // content::WebContentsObserver overrides. + void RenderFrameCreated(content::RenderFrameHost *render_frame_host) override; + +private: + friend class content::WebContentsUserData<ExtensionWebContentsObserverQt>; + WEB_CONTENTS_USER_DATA_KEY_DECL() + DISALLOW_COPY_AND_ASSIGN(ExtensionWebContentsObserverQt); +}; + +} // namespace extensions + +#endif // EXTENSION_WEB_CONTENTS_OBSERVER_QT_H_ diff --git a/src/core/extensions/extensions_api_client_qt.cpp b/src/core/extensions/extensions_api_client_qt.cpp new file mode 100644 index 000000000..731b79a63 --- /dev/null +++ b/src/core/extensions/extensions_api_client_qt.cpp @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// Portions copyright 2015 The Chromium Embedded Framework Authors. +// Portions copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "extensions_api_client_qt.h" + +#include <memory> +//#include "base/memory/ptr_util.h" +#include "extension_web_contents_observer_qt.h" +#include "components/pdf/browser/pdf_web_contents_helper.h" +#include "extensions/browser/guest_view/extensions_guest_view_manager_delegate.h" +#include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest_delegate.h" +#include "printing/print_view_manager_qt.h" + +namespace extensions { + +ExtensionsAPIClientQt::ExtensionsAPIClientQt() +{ +} + +AppViewGuestDelegate *ExtensionsAPIClientQt::CreateAppViewGuestDelegate() const +{ + // TODO(extensions): Implement to support Apps. + NOTREACHED(); + return nullptr; +} + +std::unique_ptr<guest_view::GuestViewManagerDelegate> ExtensionsAPIClientQt::CreateGuestViewManagerDelegate(content::BrowserContext *context) const +{ + return std::make_unique<guest_view::GuestViewManagerDelegate>(); +} + +std::unique_ptr<MimeHandlerViewGuestDelegate> ExtensionsAPIClientQt::CreateMimeHandlerViewGuestDelegate(MimeHandlerViewGuest *guest) const +{ + return std::make_unique<MimeHandlerViewGuestDelegate>(); +} + +void ExtensionsAPIClientQt::AttachWebContentsHelpers(content::WebContents *web_contents) const +{ + // PrefsTabHelper::CreateForWebContents(web_contents); + QtWebEngineCore::PrintViewManagerQt::CreateForWebContents(web_contents); + ExtensionWebContentsObserverQt::CreateForWebContents(web_contents); +} + +} // namespace extensions diff --git a/src/core/extensions/extensions_api_client_qt.h b/src/core/extensions/extensions_api_client_qt.h new file mode 100644 index 000000000..2fa69f539 --- /dev/null +++ b/src/core/extensions/extensions_api_client_qt.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// Portions copyright 2015 The Chromium Embedded Framework Authors. +// Portions copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef EXTENSIONS_API_CLIENT_QT_H_ +#define EXTENSIONS_API_CLIENT_QT_H_ + +#include "extensions/browser/api/extensions_api_client.h" + +namespace extensions { + +class ExtensionsAPIClientQt : public ExtensionsAPIClient +{ +public: + ExtensionsAPIClientQt(); + + // ExtensionsAPIClient implementation. + AppViewGuestDelegate *CreateAppViewGuestDelegate() const override; + std::unique_ptr<guest_view::GuestViewManagerDelegate> + CreateGuestViewManagerDelegate(content::BrowserContext *context) const override; + std::unique_ptr<MimeHandlerViewGuestDelegate> + CreateMimeHandlerViewGuestDelegate(MimeHandlerViewGuest *guest) const override; + void AttachWebContentsHelpers(content::WebContents *web_contents) const override; +}; + +} // namespace extensions + +#endif // EXTENSIONS_API_CLIENT_QT_H_ diff --git a/src/core/extensions/extensions_browser_api_provider_qt.cpp b/src/core/extensions/extensions_browser_api_provider_qt.cpp new file mode 100644 index 000000000..cc1932c64 --- /dev/null +++ b/src/core/extensions/extensions_browser_api_provider_qt.cpp @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "extensions_browser_api_provider_qt.h" + +#include "extensions/browser/api/generated_api_registration.h" + +namespace extensions { +ExtensionsBrowserAPIProviderQt::ExtensionsBrowserAPIProviderQt() = + default; +ExtensionsBrowserAPIProviderQt::~ExtensionsBrowserAPIProviderQt() = + default; + +void ExtensionsBrowserAPIProviderQt::RegisterExtensionFunctions( + ExtensionFunctionRegistry* registry) { + api::GeneratedFunctionRegistry::RegisterAll(registry); +} + + +} + diff --git a/src/core/extensions/extensions_browser_api_provider_qt.h b/src/core/extensions/extensions_browser_api_provider_qt.h new file mode 100644 index 000000000..612df3825 --- /dev/null +++ b/src/core/extensions/extensions_browser_api_provider_qt.h @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef EXTENSIONS_API_PROVIDER_QT_H +#define EXTENSIONS_API_PROVIDER_QT_H + +#include "extensions/browser/extensions_browser_api_provider.h" +#include "base/macros.h" + +namespace extensions { + +class ExtensionsBrowserAPIProviderQt : public ExtensionsBrowserAPIProvider { +public: + ExtensionsBrowserAPIProviderQt(); + ~ExtensionsBrowserAPIProviderQt() override; + + void RegisterExtensionFunctions(ExtensionFunctionRegistry *registry) override; + +private: + DISALLOW_COPY_AND_ASSIGN(ExtensionsBrowserAPIProviderQt); +}; + +} + +#endif // EXTENSIONS_API_PROVIDER_QT_H diff --git a/src/core/extensions/extensions_browser_client_qt.cpp b/src/core/extensions/extensions_browser_client_qt.cpp new file mode 100644 index 000000000..8bba4128f --- /dev/null +++ b/src/core/extensions/extensions_browser_client_qt.cpp @@ -0,0 +1,499 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// Portions copyright 2015 The Chromium Embedded Framework Authors. +// Portions copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "extensions_browser_client_qt.h" + +#include <utility> + +#include "base/files/file_path.h" +#include "base/memory/weak_ptr.h" +#include "base/path_service.h" +#include "base/strings/stringprintf.h" +#include "base/task/post_task.h" +#include "base/memory/ref_counted_memory.h" +#include "chrome/browser/profiles/profile.h" +#include "content/public/browser/browser_context.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/render_frame_host.h" +#include "extensions/browser/api/extensions_api_client.h" +#include "extensions/browser/api/runtime/runtime_api_delegate.h" +#include "extensions/browser/app_sorting.h" +#include "extensions/browser/core_extensions_browser_api_provider.h" +#include "extensions/browser/event_router.h" +#include "extensions/browser/extension_host_delegate.h" +#include "extensions/browser/extension_protocols.h" +#include "extensions/browser/mojo/interface_registration.h" +#include "extensions/browser/url_request_util.h" +#include "extensions/common/file_util.h" +#include "net/base/completion_once_callback.h" +#include "net/base/mime_util.h" +#include "net/url_request/url_request_simple_job.h" +#include "ui/base/resource/resource_bundle.h" + +#include "component_extension_resource_manager_qt.h" +#include "extension_system_factory_qt.h" +#include "extension_web_contents_observer_qt.h" +#include "extensions_api_client_qt.h" +#include "extensions_browser_api_provider_qt.h" +#include "extensions_browser_client_qt.h" +#include "web_engine_library_info.h" + +using content::BrowserContext; +using content::BrowserThread; + +namespace { + +// helpers based on implementation in chrome_url_request_util.cc: +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +void DetermineCharset(const std::string &mime_type, + const base::RefCountedMemory *data, + std::string *out_charset) +{ + if (base::StartsWith(mime_type, "text/", base::CompareCase::INSENSITIVE_ASCII)) { + // All of our HTML files should be UTF-8 and for other resource types + // (like images), charset doesn't matter. + DCHECK(base::IsStringUTF8(base::StringPiece(reinterpret_cast<const char*>(data->front()), data->size()))); + *out_charset = "utf-8"; + } +} + +// A request for an extension resource in a Chrome .pak file. These are used +// by component extensions. +class URLRequestResourceBundleJob : public net::URLRequestSimpleJob { +public: + URLRequestResourceBundleJob(net::URLRequest *request, + net::NetworkDelegate *network_delegate, + const base::FilePath &filename, + int resource_id, + const std::string &content_security_policy, + bool send_cors_header) + : net::URLRequestSimpleJob(request, network_delegate) + , filename_(filename) + , resource_id_(resource_id) + , weak_factory_(this) + { + // Leave cache headers out of resource bundle requests. + response_info_.headers = extensions::BuildHttpHeaders(content_security_policy, send_cors_header, base::Time()); + } + int GetRefCountedData(std::string* mime_type, + std::string* charset, + scoped_refptr<base::RefCountedMemory>* data, + net::CompletionOnceCallback callback) const override + { + const ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); + *data = rb.LoadDataResourceBytes(resource_id_); + + // Add the Content-Length header now that we know the resource length. + response_info_.headers->AddHeader( + base::StringPrintf("%s: %s", net::HttpRequestHeaders::kContentLength, + base::NumberToString((*data)->size()).c_str())); + + std::string* read_mime_type = new std::string; + base::PostTaskWithTraitsAndReplyWithResult( + FROM_HERE, {base::MayBlock()}, + base::BindOnce(&net::GetMimeTypeFromFile, filename_, + base::Unretained(read_mime_type)), + base::BindOnce(&URLRequestResourceBundleJob::OnMimeTypeRead, + weak_factory_.GetWeakPtr(), mime_type, charset, *data, + base::Owned(read_mime_type), std::move(callback))); + + return net::ERR_IO_PENDING; + } + + void GetResponseInfo(net::HttpResponseInfo* info) override + { + *info = response_info_; + } + +private: + ~URLRequestResourceBundleJob() override {} + + void OnMimeTypeRead(std::string *out_mime_type, + std::string *charset, + scoped_refptr<base::RefCountedMemory> data, + std::string *read_mime_type, + net::CompletionOnceCallback callback, + bool read_result) + { + response_info_.headers->AddHeader( + base::StringPrintf("%s: %s", net::HttpRequestHeaders::kContentType, + read_mime_type->c_str())); + *out_mime_type = *read_mime_type; + DetermineCharset(*read_mime_type, data.get(), charset); + int result = read_result ? net::OK : net::ERR_INVALID_URL; + std::move(callback).Run(result); + } + + // We need the filename of the resource to determine the mime type. + base::FilePath filename_; + + // The resource bundle id to load. + int resource_id_; + + net::HttpResponseInfo response_info_; + + mutable base::WeakPtrFactory<URLRequestResourceBundleJob> weak_factory_; +}; + +} // namespace + +namespace extensions { + +ExtensionsBrowserClientQt::ExtensionsBrowserClientQt() + : api_client_(new ExtensionsAPIClientQt) + , resource_manager_(new ComponentExtensionResourceManagerQt) +{ + AddAPIProvider(std::make_unique<CoreExtensionsBrowserAPIProvider>()); + AddAPIProvider(std::make_unique<ExtensionsBrowserAPIProviderQt>()); +} + +ExtensionsBrowserClientQt::~ExtensionsBrowserClientQt() +{ +} + +bool ExtensionsBrowserClientQt::IsShuttingDown() +{ + return false; +} + +bool ExtensionsBrowserClientQt::AreExtensionsDisabled(const base::CommandLine &command_line, BrowserContext *context) +{ + return false; +} + +bool ExtensionsBrowserClientQt::IsValidContext(BrowserContext *context) +{ + return true; +} + +bool ExtensionsBrowserClientQt::IsSameContext(BrowserContext *first, + BrowserContext *second) +{ + return first == second; +} + +bool ExtensionsBrowserClientQt::HasOffTheRecordContext(BrowserContext *context) +{ + return false; +} + +BrowserContext *ExtensionsBrowserClientQt::GetOffTheRecordContext(BrowserContext *context) +{ + // TODO(extensions): Do we need to support this? + return nullptr; +} + +BrowserContext *ExtensionsBrowserClientQt::GetOriginalContext(BrowserContext *context) +{ + return context; +} + +bool ExtensionsBrowserClientQt::IsGuestSession(BrowserContext *context) const +{ + return false; +} + +bool ExtensionsBrowserClientQt::IsExtensionIncognitoEnabled(const std::string &extension_id, + content::BrowserContext *context) const +{ + return false; +} + +bool ExtensionsBrowserClientQt::CanExtensionCrossIncognito(const Extension *extension, + content::BrowserContext *context) const +{ + return false; +} + +net::URLRequestJob *ExtensionsBrowserClientQt::MaybeCreateResourceBundleRequestJob(net::URLRequest *request, + net::NetworkDelegate *network_delegate, + const base::FilePath &directory_path, + const std::string &content_security_policy, + bool send_cors_header) +{ + base::FilePath resources_path; + base::FilePath relative_path; + // Try to load extension resources from chrome resource file if + // directory_path is a descendant of resources_path. resources_path + // corresponds to src/chrome/browser/resources in source tree. + if (base::PathService::Get(base::DIR_QT_LIBRARY_DATA, &resources_path) && + // Since component extension resources are included in + // component_extension_resources.pak file in resources_path, calculate + // extension relative path against resources_path. + resources_path.AppendRelativePath(directory_path, &relative_path)) { + base::FilePath request_path = extensions::file_util::ExtensionURLToRelativeFilePath(request->url()); + int resource_id = 0; + if (GetComponentExtensionResourceManager()->IsComponentExtensionResource(directory_path, request_path, &resource_id)) { + relative_path = relative_path.Append(request_path); + relative_path = relative_path.NormalizePathSeparators(); + return new URLRequestResourceBundleJob(request, + network_delegate, + relative_path, + resource_id, + content_security_policy, + send_cors_header); + } + } + return nullptr; +} + +// Return the resource relative path and id for the given request. +base::FilePath ExtensionsBrowserClientQt::GetBundleResourcePath(const network::ResourceRequest &request, + const base::FilePath &extension_resources_path, + int *resource_id) const +{ + *resource_id = 0; + // |chrome_resources_path| corresponds to src/chrome/browser/resources in + // source tree. + base::FilePath resources_path; + if (!base::PathService::Get(base::DIR_QT_LIBRARY_DATA, &resources_path)) + return base::FilePath(); + + // Since component extension resources are included in + // component_extension_resources.pak file in |chrome_resources_path|, + // calculate the extension |request_relative_path| against + // |chrome_resources_path|. + if (!resources_path.IsParent(extension_resources_path)) + return base::FilePath(); + + const base::FilePath request_relative_path = + extensions::file_util::ExtensionURLToRelativeFilePath(request.url); + if (!ExtensionsBrowserClient::Get()->GetComponentExtensionResourceManager()->IsComponentExtensionResource( + extension_resources_path, request_relative_path, resource_id)) { + return base::FilePath(); + } + DCHECK_NE(0, *resource_id); + + return request_relative_path; +} + +// Creates and starts a URLLoader to load an extension resource from the +// embedder's resource bundle (.pak) files. Used for component extensions. +void ExtensionsBrowserClientQt::LoadResourceFromResourceBundle(const network::ResourceRequest &request, + network::mojom::URLLoaderRequest loader, + const base::FilePath &resource_relative_path, + int resource_id, + const std::string &content_security_policy, + network::mojom::URLLoaderClientPtr client, + bool send_cors_header) +{ + NOTIMPLEMENTED(); +} + + +bool ExtensionsBrowserClientQt::AllowCrossRendererResourceLoad(const GURL &url, + content::ResourceType resource_type, + ui::PageTransition page_transition, + int child_id, + bool is_incognito, + const Extension *extension, + const ExtensionSet &extensions, + const ProcessMap &process_map) +{ + + if (extension && extension->id() == extension_misc::kPdfExtensionId) + return true; + + bool allowed = false; + if (url_request_util::AllowCrossRendererResourceLoad(url, resource_type, + page_transition, child_id, + is_incognito, extension, extensions, + process_map, &allowed)) { + return allowed; + } + // Couldn't determine if resource is allowed. Block the load. + return false; +} + +PrefService *ExtensionsBrowserClientQt::GetPrefServiceForContext(BrowserContext *context) +{ + return static_cast<Profile *>(context)->GetPrefs(); +} + +void ExtensionsBrowserClientQt::GetEarlyExtensionPrefsObservers(content::BrowserContext *context, + std::vector<ExtensionPrefsObserver *> *observers) const +{ +} + +ProcessManagerDelegate *ExtensionsBrowserClientQt::GetProcessManagerDelegate() const +{ + return nullptr; +} + +std::unique_ptr<ExtensionHostDelegate> ExtensionsBrowserClientQt::CreateExtensionHostDelegate() +{ + // TODO(extensions): Implement to support Apps. + NOTREACHED(); + return std::unique_ptr<ExtensionHostDelegate>(); +} + +bool ExtensionsBrowserClientQt::DidVersionUpdate(BrowserContext *context) +{ + // TODO(jamescook): We might want to tell extensions when app_shell updates. + return false; +} + +void ExtensionsBrowserClientQt::PermitExternalProtocolHandler() +{ +} + +bool ExtensionsBrowserClientQt::IsRunningInForcedAppMode() +{ + return false; +} + +bool ExtensionsBrowserClientQt::IsLoggedInAsPublicAccount() +{ + return false; +} + +ExtensionSystemProvider *ExtensionsBrowserClientQt::GetExtensionSystemFactory() +{ + return ExtensionSystemFactoryQt::GetInstance(); +} + +// void ExtensionsBrowserClientQt::RegisterExtensionFunctions(ExtensionFunctionRegistry *registry) const +//{ +// // Register core extension-system APIs. +// api::GeneratedFunctionRegistry::RegisterAll(registry); +//} + +void ExtensionsBrowserClientQt::RegisterExtensionInterfaces(service_manager::BinderRegistryWithArgs<content::RenderFrameHost *> *registry, + content::RenderFrameHost *render_frame_host, + const Extension *extension) const +{ + RegisterInterfacesForExtension(registry, render_frame_host, extension); +} + +std::unique_ptr<RuntimeAPIDelegate> ExtensionsBrowserClientQt::CreateRuntimeAPIDelegate(content::BrowserContext *context) const +{ + // TODO(extensions): Implement to support Apps. + NOTREACHED(); + return std::unique_ptr<RuntimeAPIDelegate>(); +} + +const ComponentExtensionResourceManager *ExtensionsBrowserClientQt::GetComponentExtensionResourceManager() +{ + return resource_manager_.get(); +} + +void ExtensionsBrowserClientQt::BroadcastEventToRenderers(events::HistogramValue histogram_value, + const std::string &event_name, + std::unique_ptr<base::ListValue> args) +{ + NOTIMPLEMENTED(); + // TODO : do the event routing + // event_router_forwarder_->BroadcastEventToRenderers( + // histogram_value, event_name, std::move(args), GURL()); +} + +net::NetLog *ExtensionsBrowserClientQt::GetNetLog() +{ + return nullptr; +} + +ExtensionCache *ExtensionsBrowserClientQt::GetExtensionCache() +{ + // Only used by Chrome via ExtensionService. + NOTREACHED(); + return nullptr; +} + +bool ExtensionsBrowserClientQt::IsBackgroundUpdateAllowed() +{ + return true; +} + +bool ExtensionsBrowserClientQt::IsMinBrowserVersionSupported( + const std::string &min_version) +{ + return true; +} + +bool ExtensionsBrowserClientQt::IsLockScreenContext(content::BrowserContext *context) +{ + return false; +} + +// Returns the locale used by the application. +std::string ExtensionsBrowserClientQt::GetApplicationLocale() +{ + return WebEngineLibraryInfo::getApplicationLocale(); +} + +bool ExtensionsBrowserClientQt::IsAppModeForcedForApp(const ExtensionId &id) +{ + return false; +} + +bool ExtensionsBrowserClientQt::IsInDemoMode() +{ + return false; +} + +ExtensionWebContentsObserver *ExtensionsBrowserClientQt::GetExtensionWebContentsObserver(content::WebContents *web_contents) +{ + return ExtensionWebContentsObserverQt::FromWebContents(web_contents); +} + +KioskDelegate *ExtensionsBrowserClientQt::GetKioskDelegate() +{ + NOTREACHED(); + return nullptr; +} + +bool ExtensionsBrowserClientQt::IsScreensaverInDemoMode(const std::string& app_id) +{ + return false; +} + +void ExtensionsBrowserClientQt::SetAPIClientForTest(ExtensionsAPIClient *api_client) +{ + api_client_.reset(api_client); +} + +} // namespace extensions diff --git a/src/core/extensions/extensions_browser_client_qt.h b/src/core/extensions/extensions_browser_client_qt.h new file mode 100644 index 000000000..f766b96a7 --- /dev/null +++ b/src/core/extensions/extensions_browser_client_qt.h @@ -0,0 +1,161 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// Portions copyright 2015 The Chromium Embedded Framework Authors. +// Portions copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef EXTENSIONS_BROWSER_CLIENT_QT_H_ +#define EXTENSIONS_BROWSER_CLIENT_QT_H_ + +#include "base/compiler_specific.h" +#include "extensions/browser/extensions_browser_client.h" + +namespace extensions { + +class ExtensionsAPIClient; + +// An ExtensionsBrowserClient that supports a single content::BrowserContent +// with no related incognito context. +class ExtensionsBrowserClientQt : public ExtensionsBrowserClient +{ +public: + ExtensionsBrowserClientQt(); + ~ExtensionsBrowserClientQt() override; + + // ExtensionsBrowserClient overrides: + bool IsShuttingDown() override; + bool AreExtensionsDisabled(const base::CommandLine &command_line, + content::BrowserContext *context) override; + bool IsValidContext(content::BrowserContext *context) override; + bool IsSameContext(content::BrowserContext *first, + content::BrowserContext *second) override; + bool HasOffTheRecordContext(content::BrowserContext *context) override; + content::BrowserContext *GetOffTheRecordContext(content::BrowserContext *context) override; + content::BrowserContext *GetOriginalContext(content::BrowserContext *context) override; + bool IsGuestSession(content::BrowserContext *context) const override; + bool IsExtensionIncognitoEnabled(const std::string &extension_id, content::BrowserContext *context) const override; + bool CanExtensionCrossIncognito(const Extension *extension, content::BrowserContext *context) const override; + net::URLRequestJob *MaybeCreateResourceBundleRequestJob(net::URLRequest *request, + net::NetworkDelegate *network_delegate, + const base::FilePath &directory_path, + const std::string &content_security_policy, + bool send_cors_header) override; + bool AllowCrossRendererResourceLoad(const GURL &url, + content::ResourceType resource_type, + ui::PageTransition page_transition, + int child_id, + bool is_incognito, + const Extension *extension, + const ExtensionSet &extensions, + const ProcessMap &process_map) override; + PrefService *GetPrefServiceForContext(content::BrowserContext *context) override; + void GetEarlyExtensionPrefsObservers(content::BrowserContext *context, std::vector<ExtensionPrefsObserver *> *observers) const + override; + ProcessManagerDelegate *GetProcessManagerDelegate() const override; + std::unique_ptr<ExtensionHostDelegate> + CreateExtensionHostDelegate() override; + bool DidVersionUpdate(content::BrowserContext *context) override; + void PermitExternalProtocolHandler() override; + bool IsRunningInForcedAppMode() override; + bool IsLoggedInAsPublicAccount() override; + ExtensionSystemProvider *GetExtensionSystemFactory() override; +// void RegisterExtensionFunctions(ExtensionFunctionRegistry *registry) const; + std::unique_ptr<RuntimeAPIDelegate> CreateRuntimeAPIDelegate(content::BrowserContext *context) const override; + void RegisterExtensionInterfaces(service_manager::BinderRegistryWithArgs<content::RenderFrameHost *> *registry, + content::RenderFrameHost *render_frame_host, + const Extension *extension) const override; + const ComponentExtensionResourceManager * + GetComponentExtensionResourceManager() override; + void BroadcastEventToRenderers(events::HistogramValue histogram_value, + const std::string &event_name, + std::unique_ptr<base::ListValue> args) override; + net::NetLog *GetNetLog() override; + ExtensionCache *GetExtensionCache() override; + bool IsBackgroundUpdateAllowed() override; + bool IsMinBrowserVersionSupported(const std::string &min_version) override; + ExtensionWebContentsObserver *GetExtensionWebContentsObserver( + content::WebContents *web_contents) override; + KioskDelegate *GetKioskDelegate() override; + + // Whether the browser context is associated with Chrome OS lock screen. + bool IsLockScreenContext(content::BrowserContext *context) override; + + bool IsAppModeForcedForApp(const ExtensionId &id) override; + bool IsInDemoMode() override; + + // Return the resource relative path and id for the given request. + base::FilePath GetBundleResourcePath(const network::ResourceRequest &request, + const base::FilePath &extension_resources_path, + int *resource_id) const override; + + // Creates and starts a URLLoader to load an extension resource from the + // embedder's resource bundle (.pak) files. Used for component extensions. + void LoadResourceFromResourceBundle(const network::ResourceRequest &request, + network::mojom::URLLoaderRequest loader, + const base::FilePath &resource_relative_path, + int resource_id, + const std::string &content_security_policy, + network::mojom::URLLoaderClientPtr client, + bool send_cors_header) override; + + // Returns the locale used by the application. + std::string GetApplicationLocale() override; + + bool IsScreensaverInDemoMode(const std::string& app_id) override; + + // Sets the API client. + void SetAPIClientForTest(ExtensionsAPIClient *api_client); + +private: + // Support for extension APIs. + std::unique_ptr<ExtensionsAPIClient> api_client_; + + // Resource manager used to supply resources from pak files. + std::unique_ptr<ComponentExtensionResourceManager> resource_manager_; + + //scoped_refptr<EventRouterForwarder> event_router_forwarder_; + + DISALLOW_COPY_AND_ASSIGN(ExtensionsBrowserClientQt); +}; + +} // namespace extensions + +#endif // EXTENSIONS_BROWSER_CLIENT_QT_H_ diff --git a/src/core/extensions/mime_handler_view_guest_delegate_qt.cpp b/src/core/extensions/mime_handler_view_guest_delegate_qt.cpp new file mode 100644 index 000000000..438b8a83e --- /dev/null +++ b/src/core/extensions/mime_handler_view_guest_delegate_qt.cpp @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// Portions copyright 2015 The Chromium Embedded Framework Authors. +// Portions copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mime_handler_view_guest_delegate_qt.h" + +#include "content/browser/browser_plugin/browser_plugin_guest.h" +#include "content/browser/web_contents/web_contents_impl.h" +#include "content/public/browser/web_contents.h" +#include "content/public/common/context_menu_params.h" +#include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h" + +namespace extensions { + +MimeHandlerViewGuestDelegateQt::MimeHandlerViewGuestDelegateQt(MimeHandlerViewGuest *guest) + : MimeHandlerViewGuestDelegate() +{ +} + +MimeHandlerViewGuestDelegateQt::~MimeHandlerViewGuestDelegateQt() +{ +} + +bool MimeHandlerViewGuestDelegateQt::HandleContextMenu(content::WebContents *web_contents, const content::ContextMenuParams ¶ms) +{ + content::ContextMenuParams new_params = params; + + gfx::Point guest_coordinates = + static_cast<content::WebContentsImpl *>(web_contents)->GetBrowserPluginGuest()->GetScreenCoordinates(gfx::Point()); + + // Adjust (x,y) position for offset from guest to embedder. + new_params.x += guest_coordinates.x(); + new_params.y += guest_coordinates.y(); + + return false; +} + +} // namespace extensions diff --git a/src/core/extensions/mime_handler_view_guest_delegate_qt.h b/src/core/extensions/mime_handler_view_guest_delegate_qt.h new file mode 100644 index 000000000..b679c7a38 --- /dev/null +++ b/src/core/extensions/mime_handler_view_guest_delegate_qt.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// Portions copyright 2015 The Chromium Embedded Framework Authors. +// Portions copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MIME_HANDLER_VIEW_GUEST_DELEGATE_QT_H_ +#define MIME_HANDLER_VIEW_GUEST_DELEGATE_QT_H_ + +#include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest_delegate.h" +#include "content/browser/web_contents/web_contents_view.h" +#include "content/public/browser/web_contents.h" + +namespace content { +struct ContextMenuParams; +} + +namespace extensions { +class MimeHandlerViewGuest; + +class MimeHandlerViewGuestDelegateQt : public MimeHandlerViewGuestDelegate +{ +public: + explicit MimeHandlerViewGuestDelegateQt(MimeHandlerViewGuest *guest); + ~MimeHandlerViewGuestDelegateQt() override; + + bool HandleContextMenu(content::WebContents *web_contents, + const content::ContextMenuParams ¶ms) override; + +private: + MimeHandlerViewGuest *guest_; // Owns us. + + DISALLOW_COPY_AND_ASSIGN(MimeHandlerViewGuestDelegateQt); +}; + +} // namespace extensions + +#endif // MIME_HANDLER_VIEW_GUEST_DELEGATE_QT_H_ diff --git a/src/core/extensions/pdf_web_contents_helper_client_qt.h b/src/core/extensions/pdf_web_contents_helper_client_qt.h new file mode 100644 index 000000000..a22feb138 --- /dev/null +++ b/src/core/extensions/pdf_web_contents_helper_client_qt.h @@ -0,0 +1,29 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PDF_WEB_CONTENTS_HELPER_CLIENT_QT_H_ +#define PDF_WEB_CONTENTS_HELPER_CLIENT_QT_H_ + +#include "base/macros.h" +#include "components/pdf/browser/pdf_web_contents_helper_client.h" + +namespace extensions { + +class PDFWebContentsHelperClientQt : public pdf::PDFWebContentsHelperClient { +public: + PDFWebContentsHelperClientQt(); + ~PDFWebContentsHelperClientQt() override; + +private: + // pdf::PDFWebContentsHelperClient: + void UpdateContentRestrictions(content::WebContents* contents, int content_restrictions) override; + void OnPDFHasUnsupportedFeature(content::WebContents* contents) override; + void OnSaveURL(content::WebContents* contents) override; + + DISALLOW_COPY_AND_ASSIGN(PDFWebContentsHelperClientQt); +}; + +} // namespace extensions + +#endif // PDF_WEB_CONTENTS_HELPER_CLIENT_QT_H_ diff --git a/src/core/favicon_manager.h b/src/core/favicon_manager.h index 60d194c4b..75d6aa75b 100644 --- a/src/core/favicon_manager.h +++ b/src/core/favicon_manager.h @@ -82,7 +82,7 @@ namespace QtWebEngineCore { class WebContentsAdapterClient; // Based on src/3rdparty/chromium/content/public/common/favicon_url.h -class QWEBENGINECORE_PRIVATE_EXPORT FaviconInfo { +class Q_WEBENGINECORE_PRIVATE_EXPORT FaviconInfo { public: enum FaviconTypeFlag { InvalidIcon = 0, @@ -109,7 +109,7 @@ public: }; -class QWEBENGINECORE_PRIVATE_EXPORT FaviconManager { +class Q_WEBENGINECORE_PRIVATE_EXPORT FaviconManager { public: FaviconManager(content::WebContents *, WebContentsAdapterClient *); diff --git a/src/core/file_picker_controller.cpp b/src/core/file_picker_controller.cpp index 3ded5ec41..63b93c502 100644 --- a/src/core/file_picker_controller.cpp +++ b/src/core/file_picker_controller.cpp @@ -39,8 +39,12 @@ #include "file_picker_controller.h" #include "type_conversion.h" +#if defined(OS_WIN) +#include "base/files/file_path.h" +#endif #include "content/browser/renderer_host/render_view_host_impl.h" #include "content/browser/web_contents/web_contents_impl.h" +#include "content/public/browser/file_select_listener.h" #include <QFileInfo> #include <QDir> @@ -49,40 +53,61 @@ namespace QtWebEngineCore { -FilePickerController::FilePickerController(FileChooserMode mode, content::RenderFrameHost *frameHost, const QString &defaultFileName, const QStringList &acceptedMimeTypes, QObject *parent) +FilePickerController::FilePickerController(FileChooserMode mode, std::unique_ptr<content::FileSelectListener> listener, const QString &defaultFileName, const QStringList &acceptedMimeTypes, QObject *parent) : QObject(parent) , m_defaultFileName(defaultFileName) , m_acceptedMimeTypes(acceptedMimeTypes) - , m_frameHost(frameHost) + , m_listener(std::move(listener)) , m_mode(mode) { } +FilePickerController::~FilePickerController() = default; + void FilePickerController::accepted(const QStringList &files) { - FilePickerController::filesSelectedInChooser(files, m_frameHost); + QStringList stringList; + stringList.reserve(files.count()); + + for (const QString &urlString : files) { + // We accept strings on both absolute-path and file-URL form: + if (QDir::isAbsolutePath(urlString)) { + QString absolutePath = QDir::fromNativeSeparators(urlString); +#if defined(OS_WIN) + if (absolutePath.at(0).isLetter() && absolutePath.at(1) == QLatin1Char(':') && !base::FilePath::IsSeparator(absolutePath.at(2).toLatin1())) + qWarning("Ignoring invalid item in FilePickerController::accepted(QStringList): %s", qPrintable(urlString)); + else +#endif + stringList.append(absolutePath); + } else { + QUrl url(urlString, QUrl::StrictMode); + if (url.isLocalFile() && QDir::isAbsolutePath(url.toLocalFile())) { + QString absolutePath = url.toLocalFile(); +#if defined(OS_WIN) + if (absolutePath.at(0).isLetter() && absolutePath.at(1) == QLatin1Char(':') && !base::FilePath::IsSeparator(absolutePath.at(2).toLatin1())) + qWarning("Ignoring invalid item in FilePickerController::accepted(QStringList): %s", qPrintable(urlString)); + else +#endif + stringList.append(absolutePath); + } else + qWarning("Ignoring invalid item in FilePickerController::accepted(QStringList): %s", qPrintable(urlString)); + } + } + + FilePickerController::filesSelectedInChooser(stringList); } void FilePickerController::accepted(const QVariant &files) { - QStringList stringList; - - if (files.canConvert(QVariant::StringList)) { - stringList = files.toStringList(); - } else if (files.canConvert<QList<QUrl> >()) { - const QList<QUrl> urls = files.value<QList<QUrl>>(); - for (const QUrl &url : urls) - stringList.append(url.toLocalFile()); - } else { + if (!files.canConvert(QVariant::StringList)) qWarning("An unhandled type '%s' was provided in FilePickerController::accepted(QVariant)", files.typeName()); - } - FilePickerController::filesSelectedInChooser(stringList, m_frameHost); + accepted(files.toStringList()); } void FilePickerController::rejected() { - FilePickerController::filesSelectedInChooser(QStringList(), m_frameHost); + FilePickerController::filesSelectedInChooser(QStringList()); } static QStringList listRecursively(const QDir &dir) @@ -99,19 +124,30 @@ static QStringList listRecursively(const QDir &dir) return ret; } -ASSERT_ENUMS_MATCH(FilePickerController::Open, content::FileChooserParams::Open) -ASSERT_ENUMS_MATCH(FilePickerController::OpenMultiple, content::FileChooserParams::OpenMultiple) -ASSERT_ENUMS_MATCH(FilePickerController::UploadFolder, content::FileChooserParams::UploadFolder) -ASSERT_ENUMS_MATCH(FilePickerController::Save, content::FileChooserParams::Save) +ASSERT_ENUMS_MATCH(FilePickerController::Open, blink::mojom::FileChooserParams_Mode::kOpen) +ASSERT_ENUMS_MATCH(FilePickerController::OpenMultiple, blink::mojom::FileChooserParams_Mode::kOpenMultiple) +ASSERT_ENUMS_MATCH(FilePickerController::UploadFolder, blink::mojom::FileChooserParams_Mode::kUploadFolder) +ASSERT_ENUMS_MATCH(FilePickerController::Save, blink::mojom::FileChooserParams_Mode::kSave) -void FilePickerController::filesSelectedInChooser(const QStringList &filesList, content::RenderFrameHost *frameHost) +void FilePickerController::filesSelectedInChooser(const QStringList &filesList) { - Q_ASSERT(frameHost); QStringList files(filesList); if (this->m_mode == UploadFolder && !filesList.isEmpty() && QFileInfo(filesList.first()).isDir()) // Enumerate the directory files = listRecursively(QDir(filesList.first())); - frameHost->FilesSelectedInChooser(toVector<content::FileChooserFileInfo>(files), static_cast<content::FileChooserParams::Mode>(this->m_mode)); + + std::vector<blink::mojom::FileChooserFileInfoPtr> chooser_files; + for (const auto &file : qAsConst(files)) { + chooser_files.push_back(blink::mojom::FileChooserFileInfo::NewNativeFile( + blink::mojom::NativeFileInfo::New(toFilePath(file), base::string16()))); + } + + if (files.isEmpty()) + m_listener->FileSelectionCanceled(); + else + m_listener->FileSelected(std::move(chooser_files), + /* FIXME? */ base::FilePath(), + static_cast<blink::mojom::FileChooserParams::Mode>(this->m_mode)); } QStringList FilePickerController::acceptedMimeTypes() const diff --git a/src/core/file_picker_controller.h b/src/core/file_picker_controller.h index 7507cf358..dc8c0eddf 100644 --- a/src/core/file_picker_controller.h +++ b/src/core/file_picker_controller.h @@ -52,16 +52,19 @@ #define FILE_PICKER_CONTROLLER_H #include "qtwebenginecoreglobal_p.h" + +#include <memory> + #include <QObject> #include <QStringList> namespace content { - class RenderFrameHost; + class FileSelectListener; } namespace QtWebEngineCore { -class QWEBENGINECORE_PRIVATE_EXPORT FilePickerController : public QObject { +class Q_WEBENGINECORE_PRIVATE_EXPORT FilePickerController : public QObject { Q_OBJECT public: enum FileChooserMode { @@ -71,7 +74,8 @@ public: Save }; - FilePickerController(FileChooserMode mode, content::RenderFrameHost *contents, const QString &defaultFileName, const QStringList &acceptedMimeTypes, QObject * = 0); + FilePickerController(FileChooserMode mode, std::unique_ptr<content::FileSelectListener> listener, const QString &defaultFileName, const QStringList &acceptedMimeTypes, QObject * = 0); + ~FilePickerController() override; QStringList acceptedMimeTypes() const; QString defaultFileName() const; FileChooserMode mode() const; @@ -82,10 +86,10 @@ public Q_SLOTS: void rejected(); private: - void filesSelectedInChooser(const QStringList &filesList, content::RenderFrameHost *contents); + void filesSelectedInChooser(const QStringList &filesList); QString m_defaultFileName; QStringList m_acceptedMimeTypes; - content::RenderFrameHost *m_frameHost; + std::unique_ptr<content::FileSelectListener> m_listener; FileChooserMode m_mode; }; diff --git a/src/core/gn_run.pro b/src/core/gn_run.pro index 9860c4541..0219a2be9 100644 --- a/src/core/gn_run.pro +++ b/src/core/gn_run.pro @@ -49,7 +49,7 @@ build_pass|!debug_and_release { ninjaflags = $$(NINJAFLAGS) isEmpty(ninjaflags):!silent: ninjaflags = "-v" - runninja.commands = $$NINJA $$ninjaflags -C $$gn_build_root QtWebEngineCore + runninja.commands = $$NINJA $$ninjaflags \$\(NINJAJOBS\) -C $$gn_build_root QtWebEngineCore QMAKE_EXTRA_TARGETS += runninja build_pass:build_all: default_target.target = all diff --git a/src/core/javascript_dialog_controller.h b/src/core/javascript_dialog_controller.h index 1ba94e095..ba9f51944 100644 --- a/src/core/javascript_dialog_controller.h +++ b/src/core/javascript_dialog_controller.h @@ -59,7 +59,7 @@ namespace QtWebEngineCore { class JavaScriptDialogControllerPrivate; -class QWEBENGINECORE_PRIVATE_EXPORT JavaScriptDialogController : public QObject { +class Q_WEBENGINECORE_PRIVATE_EXPORT JavaScriptDialogController : public QObject { Q_OBJECT public: ~JavaScriptDialogController(); diff --git a/src/core/locked_ptr.h b/src/core/locked_ptr.h new file mode 100644 index 000000000..46d89819b --- /dev/null +++ b/src/core/locked_ptr.h @@ -0,0 +1,301 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef LOCKED_PTR_H +#define LOCKED_PTR_H + +#include <base/bind_internal.h> + +#include <QtCore/qreadwritelock.h> + +namespace base { + +struct LockedPtrCore +{ + LockedPtrCore(uintptr_t data) : data(data) {} + + std::atomic<size_t> refCount{1}; + // Atomic so that WeakLockedPtr::get can still read it. + std::atomic<uintptr_t> data; + QReadWriteLock lock{QReadWriteLock::Recursive}; +}; + +enum class LockedPtrMode { Weak, Shared, Exclusive }; + +template<class T, LockedPtrMode mode> class LockedPtr; + +// A WeakLockedPtr<T> is something like shared_ptr<T*>. The T* value can only be +// accessed by atomic read. +template<class T> using WeakLockedPtr = LockedPtr<T, LockedPtrMode::Weak>; + +// A SharedLockedPtr<T> is like WeakLockedPtr<T>, but the T* value is prevented +// from changing for the lifetime of the SharedLockedPtr by holding a +// shared-exclusive mutex in shared mode. +template<class T> using SharedLockedPtr = LockedPtr<T, LockedPtrMode::Shared>; + +// An ExclusiveLockedPtr<T> is like SharedLockedPtr<T>, but the mutex is held in +// exclusive mode. Only in this mode can the T* value be changed. +template<class T> using ExclusiveLockedPtr = LockedPtr<T, LockedPtrMode::Exclusive>; + +template<class T, LockedPtrMode mode> +class LockedPtr +{ + template<class T1> + static constexpr bool canConstructFrom = + std::is_same<T, T1>::value || + std::is_same<T, const T1>::value; + +public: + constexpr LockedPtr() {} + constexpr LockedPtr(std::nullptr_t) {} + + LockedPtr(const LockedPtr &that) + { + m_core = that.m_core; + lock(); + } + + LockedPtr &operator=(const LockedPtr &that) + { + unlock(); + m_core = that.m_core; + lock(); + } + + LockedPtr(LockedPtr &&that) + { + m_core = that.m_core; + that.m_core = nullptr; + } + + LockedPtr &operator=(LockedPtr &&that) + { + unlock(); + m_core = that.m_core; + that.m_core = nullptr; + } + + template<class T1, LockedPtrMode mode1, + class Enable = std::enable_if_t<canConstructFrom<T1>>> + LockedPtr(const LockedPtr<T1, mode1> &that) + { + m_core = that.m_core; + lock(); + } + + template<class T1, LockedPtrMode mode1, + class Enable = std::enable_if_t<canConstructFrom<T1>>> + LockedPtr &operator=(const LockedPtr<T1, mode1> &that) + { + unlock(); + m_core = that.m_core; + lock(); + } + + template<class T1, + class Enable = std::enable_if_t<canConstructFrom<T1>>> + LockedPtr(LockedPtr<T1, mode> &&that) + { + m_core = that.m_core; + that.m_core = nullptr; + } + + template<class T1, + class Enable = std::enable_if_t<canConstructFrom<T1>>> + LockedPtr &operator=(LockedPtr<T1, mode> &&that) + { + unlock(); + m_core = that.m_core; + that.m_core = nullptr; + } + + ~LockedPtr() + { + unlock(); + } + + T *get() const + { + if (m_core) { + if (mode == LockedPtrMode::Weak) + return reinterpret_cast<T *>(m_core->data.load(std::memory_order_acquire)); + else + return reinterpret_cast<T *>(m_core->data.load(std::memory_order_relaxed)); + } + return nullptr; + } + + void set(T *value) + { + static_assert(mode == LockedPtrMode::Exclusive, ""); + DCHECK(m_core); + m_core->data.store(reinterpret_cast<uintptr_t>(value), std::memory_order_release); + } + + T &operator*() const { return *get(); } + T *operator->() const { return get(); } + explicit operator bool() const { return get(); } + + bool MaybeValid() const { return m_core; } + + static LockedPtr create(T *value) + { + return new LockedPtrCore(reinterpret_cast<uintptr_t>(value)); + } + +private: + template<class T1, LockedPtrMode mode1> friend class LockedPtr; + + LockedPtr(LockedPtrCore *core) + : m_core(core) + {} + + void lock() + { + if (m_core) { + ++m_core->refCount; + + if (mode == LockedPtrMode::Shared) + m_core->lock.lockForRead(); + else if (mode == LockedPtrMode::Exclusive) + m_core->lock.lockForWrite(); + } + } + + void unlock() + { + if (m_core) { + if (mode != LockedPtrMode::Weak) + m_core->lock.unlock(); + + if (--m_core->refCount == 0) + delete m_core; + } + } + + LockedPtrCore *m_core = nullptr; +}; + +// This makes Bind check the pointer before calling the functor. +template<class T> +struct IsWeakReceiver<WeakLockedPtr<T>> : std::true_type {}; + +// By converting the WeakLockedPtr into a SharedLockedPtr we prevent the +// pointed-to object from being destroyed during the base::Callback::Run call. +// +// Unwrap() is called before checking the pointer, so there's no race condition. +template<class T> +struct BindUnwrapTraits<WeakLockedPtr<T>> +{ + static SharedLockedPtr<T> Unwrap(const WeakLockedPtr<T> &o) + { + return o; + } +}; + +// Like base::WeakPtrFactory, but InvalidateWeakPtrs *waits* until all currently +// executing base::Callbacks are finished. Queued up base::Callbacks are still +// canceled, exactly like with WeakPtrFactory. +// +// Consider, for example, the function +// +// void fun() +// { +// MyClass *myClass = new MyClass; +// myClass->scheduleDoStuff(); +// delete myClass; // ??? +// } +// +// where +// +// class MyClass +// { +// public: +// void scheduleDoStuff() +// { +// content::BrowserThread::PostTask( +// content::BrowserThread::IO, FROM_HERE, +// base::BindOnce(&MyClass::doStuff, m_weakPtrFactory.GetWeakPtr())); +// } +// void doStuff(); +// private: +// //base::WeakPtrFactory m_weakPtrFactory{this}; +// base::LockedPtrFactory m_weakPtrFactory{this}; +// }; +// +// What happens if the 'delete myClass' line is executed concurrently with +// MyClass::doStuff? +// +// With WeakPtrs we get a segfault or perhaps memory corruption. +// +// With LockedPtrs we get no crash and no corruption: LockedPtrFactory's +// destructor will wait until doStuff is done before continuing. +template<class T> +class LockedPtrFactory +{ +public: + explicit LockedPtrFactory(T *value) + : m_ptr(WeakLockedPtr<T>::create(value)) + {} + + ~LockedPtrFactory() + { + InvalidateWeakPtrs(); + } + + WeakLockedPtr<T> GetWeakPtr() { return m_ptr; } + WeakLockedPtr<const T> GetWeakPtr() const { return m_ptr; } + SharedLockedPtr<T> GetSharedPtr() { return m_ptr; } + SharedLockedPtr<const T> GetSharedPtr() const { return m_ptr; } + ExclusiveLockedPtr<T> GetExclusivePtr() { return m_ptr; } + ExclusiveLockedPtr<const T> GetExclusivePtr() const { return m_ptr; } + + void InvalidateWeakPtrs() + { + if (ExclusiveLockedPtr<T> ptr = m_ptr) + ptr.set(nullptr); + } + +private: + WeakLockedPtr<T> m_ptr; +}; + +} // namespace base + +#endif // !LOCKED_PTR_H diff --git a/src/core/login_delegate_qt.cpp b/src/core/login_delegate_qt.cpp index 9659b354a..0050f87c7 100644 --- a/src/core/login_delegate_qt.cpp +++ b/src/core/login_delegate_qt.cpp @@ -43,17 +43,32 @@ #include "login_delegate_qt.h" +#include "base/task/post_task.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 "content/public/browser/render_view_host.h" #include "content/public/browser/resource_dispatcher_host.h" #include "content/public/browser/resource_request_info.h" +#include "content/public/browser/stream_info.h" +#include "extensions/buildflags/buildflags.h" +#if BUILDFLAG(ENABLE_EXTENSIONS) +#include "extensions/browser/info_map.h" +#include "extensions/common/extension.h" +#include "extensions/common/manifest_handlers/mime_types_handler.h" +#endif // BUILDFLAG(ENABLE_EXTENSIONS) + #include "net/url_request/url_request.h" #include "authentication_dialog_controller.h" #include "authentication_dialog_controller_p.h" +#if BUILDFLAG(ENABLE_EXTENSIONS) +#include "extensions/extension_system_qt.h" +#endif // BUILDFLAG(ENABLE_EXTENSIONS) +#include "resource_context_qt.h" #include "type_conversion.h" #include "web_contents_view_qt.h" +#include "web_engine_context.h" namespace QtWebEngineCore { @@ -66,14 +81,9 @@ LoginDelegateQt::LoginDelegateQt( : m_authInfo(authInfo) , m_url(url) , m_auth_required_callback(std::move(auth_required_callback)) + , m_webContentsGetter(web_contents_getter) { Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); - - content::BrowserThread::PostTask( - content::BrowserThread::UI, FROM_HERE, - base::Bind(&LoginDelegateQt::triggerDialog, - this, - web_contents_getter)); } LoginDelegateQt::~LoginDelegateQt() @@ -81,6 +91,13 @@ LoginDelegateQt::~LoginDelegateQt() Q_ASSERT(m_dialogController.isNull()); } +void LoginDelegateQt::triggerDialog() +{ + base::PostTaskWithTraits( + FROM_HERE, { content::BrowserThread::UI }, + base::BindOnce(&LoginDelegateQt::triggerDialogOnUI, this)); +} + void LoginDelegateQt::OnRequestCancelled() { destroy(); @@ -102,16 +119,34 @@ QString LoginDelegateQt::host() const return QString::fromStdString(m_authInfo->challenger.host()); } +int LoginDelegateQt::port() const +{ + return m_authInfo->challenger.port(); +} + bool LoginDelegateQt::isProxy() const { return m_authInfo->is_proxy; } -void LoginDelegateQt::triggerDialog(const content::ResourceRequestInfo::WebContentsGetter &webContentsGetter) +void LoginDelegateQt::triggerDialogOnUI() { Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + + if (isProxy()) { + // workaround for 'ws' redefined symbols when including QNetworkProxy + auto authentication = WebEngineContext::qProxyNetworkAuthentication(host(), port()); + if (std::get<0>(authentication)) { + base::PostTaskWithTraits( + FROM_HERE, { content::BrowserThread::IO }, + base::BindOnce(&LoginDelegateQt::sendAuthToRequester, this, true, + std::get<1>(authentication), std::get<2>(authentication))); + + return; + } + } content::WebContentsImpl *webContents = - static_cast<content::WebContentsImpl *>(webContentsGetter.Run()); + static_cast<content::WebContentsImpl *>(m_webContentsGetter.Run()); if (!webContents) return; WebContentsAdapterClient *client = WebContentsViewQt::from(webContents->GetView())->client(); diff --git a/src/core/login_delegate_qt.h b/src/core/login_delegate_qt.h index 9ce5df843..3a9c073cd 100644 --- a/src/core/login_delegate_qt.h +++ b/src/core/login_delegate_qt.h @@ -66,24 +66,28 @@ public: ~LoginDelegateQt(); + void triggerDialog(); + // LoginDelegate implementation void OnRequestCancelled() override; QUrl url() const; QString realm() const; QString host() const; + int port() const; bool isProxy() const; void sendAuthToRequester(bool success, const QString &user, const QString &password); private: - void triggerDialog(const content::ResourceRequestInfo::WebContentsGetter &); + void triggerDialogOnUI(); void destroy(); scoped_refptr<net::AuthChallengeInfo> m_authInfo; GURL m_url; LoginAuthRequiredCallback m_auth_required_callback; + content::ResourceRequestInfo::WebContentsGetter m_webContentsGetter; // This member is used to keep authentication dialog controller alive until // authorization is sent or cancelled. diff --git a/src/core/media_capture_devices_dispatcher.cpp b/src/core/media_capture_devices_dispatcher.cpp index 2bac62084..ecc46f244 100644 --- a/src/core/media_capture_devices_dispatcher.cpp +++ b/src/core/media_capture_devices_dispatcher.cpp @@ -49,17 +49,16 @@ #include "web_engine_settings.h" #include "base/strings/utf_string_conversions.h" -#include "chrome/browser/media/webrtc/desktop_streams_registry.h" #include "content/browser/web_contents/web_contents_impl.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/media_capture_devices.h" #include "content/public/browser/notification_service.h" #include "content/public/browser/notification_source.h" #include "content/public/browser/notification_types.h" #include "content/public/browser/render_process_host.h" #include "content/public/common/origin_util.h" -#include "content/public/common/media_stream_request.h" #include "media/audio/audio_device_description.h" #include "media/audio/audio_manager_base.h" #include "ui/base/l10n/l10n_util.h" @@ -74,13 +73,12 @@ namespace QtWebEngineCore { using content::BrowserThread; -using content::MediaStreamDevices; namespace { -const content::MediaStreamDevice *findDeviceWithId(const content::MediaStreamDevices &devices, const std::string &deviceId) +const blink::MediaStreamDevice *findDeviceWithId(const blink::MediaStreamDevices &devices, const std::string &deviceId) { - content::MediaStreamDevices::const_iterator iter = devices.begin(); + blink::MediaStreamDevices::const_iterator iter = devices.begin(); for (; iter != devices.end(); ++iter) { if (iter->id == deviceId) { return &(*iter); @@ -90,21 +88,21 @@ const content::MediaStreamDevice *findDeviceWithId(const content::MediaStreamDev } // Based on chrome/browser/media/desktop_capture_access_handler.cc: -void getDevicesForDesktopCapture(content::MediaStreamDevices *devices, content::DesktopMediaID mediaId, bool captureAudio) +void getDevicesForDesktopCapture(blink::MediaStreamDevices *devices, content::DesktopMediaID mediaId, bool captureAudio) { DCHECK_CURRENTLY_ON(BrowserThread::UI); // Add selected desktop source to the list. - devices->push_back(content::MediaStreamDevice(content::MEDIA_DESKTOP_VIDEO_CAPTURE, mediaId.ToString(), "Screen")); + devices->push_back(blink::MediaStreamDevice(blink::MEDIA_GUM_DESKTOP_VIDEO_CAPTURE, mediaId.ToString(), "Screen")); if (captureAudio) { if (mediaId.type == content::DesktopMediaID::TYPE_WEB_CONTENTS) { devices->push_back( - content::MediaStreamDevice(content::MEDIA_DESKTOP_AUDIO_CAPTURE, - mediaId.ToString(), "Tab audio")); + blink::MediaStreamDevice(blink::MEDIA_GUM_DESKTOP_AUDIO_CAPTURE, + mediaId.ToString(), "Tab audio")); } else { // Use the special loopback device ID for system audio capture. - devices->push_back(content::MediaStreamDevice( - content::MEDIA_DESKTOP_AUDIO_CAPTURE, + devices->push_back(blink::MediaStreamDevice( + blink::MEDIA_GUM_DESKTOP_AUDIO_CAPTURE, media::AudioDeviceDescription::kLoopbackInputDeviceId, "System Audio")); } @@ -155,14 +153,14 @@ WebContentsAdapterClient::MediaRequestFlags mediaRequestFlagsForRequest(const co { WebContentsAdapterClient::MediaRequestFlags requestFlags = WebContentsAdapterClient::MediaNone; - if (request.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE) + if (request.audio_type == blink::MEDIA_DEVICE_AUDIO_CAPTURE) requestFlags |= WebContentsAdapterClient::MediaAudioCapture; - else if (request.audio_type == content::MEDIA_DESKTOP_AUDIO_CAPTURE) + else if (request.audio_type == blink::MEDIA_GUM_DESKTOP_AUDIO_CAPTURE) requestFlags |= WebContentsAdapterClient::MediaDesktopAudioCapture; - if (request.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE) + if (request.video_type == blink::MEDIA_DEVICE_VIDEO_CAPTURE) requestFlags |= WebContentsAdapterClient::MediaVideoCapture; - else if (request.video_type == content::MEDIA_DESKTOP_VIDEO_CAPTURE) + else if (request.video_type == blink::MEDIA_GUM_DESKTOP_VIDEO_CAPTURE) requestFlags |= WebContentsAdapterClient::MediaDesktopVideoCapture; return requestFlags; @@ -185,7 +183,7 @@ void MediaCaptureDevicesDispatcher::handleMediaAccessPermissionResponse(content: { DCHECK_CURRENTLY_ON(BrowserThread::UI); - content::MediaStreamDevices devices; + blink::MediaStreamDevices devices; auto it = m_pendingRequests.find(webContents); if (it == m_pendingRequests.end() || it->second.empty()) return; @@ -212,11 +210,12 @@ void MediaCaptureDevicesDispatcher::handleMediaAccessPermissionResponse(content: if (securityOriginsMatch) { if (microphoneRequested || webcamRequested) { switch (request.request_type) { - case content::MEDIA_OPEN_DEVICE_PEPPER_ONLY: + case blink::MEDIA_OPEN_DEVICE_PEPPER_ONLY: getDefaultDevices("", "", microphoneRequested, webcamRequested, &devices); break; - case content::MEDIA_DEVICE_ACCESS: - case content::MEDIA_GENERATE_STREAM: + case blink::MEDIA_DEVICE_ACCESS: + case blink::MEDIA_DEVICE_UPDATE: + case blink::MEDIA_GENERATE_STREAM: getDefaultDevices(request.requested_audio_device_id, request.requested_video_device_id, microphoneRequested, webcamRequested, &devices); break; @@ -233,11 +232,12 @@ void MediaCaptureDevicesDispatcher::handleMediaAccessPermissionResponse(content: // Post a task to process next queued request. It has to be done // asynchronously to make sure that calling infobar is not destroyed until // after this function returns. - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, base::BindOnce(&MediaCaptureDevicesDispatcher::ProcessQueuedAccessRequest, base::Unretained(this), webContents)); + base::PostTaskWithTraits(FROM_HERE, {BrowserThread::UI}, + base::BindOnce(&MediaCaptureDevicesDispatcher::ProcessQueuedAccessRequest, + base::Unretained(this), webContents)); } - std::move(callback).Run(devices, devices.empty() ? content::MEDIA_DEVICE_INVALID_STATE : content::MEDIA_DEVICE_OK, + std::move(callback).Run(devices, devices.empty() ? blink::MEDIA_DEVICE_INVALID_STATE : blink::MEDIA_DEVICE_OK, std::unique_ptr<content::MediaStreamUI>()); } @@ -275,17 +275,17 @@ void MediaCaptureDevicesDispatcher::processMediaAccessRequest(WebContentsAdapter DCHECK_CURRENTLY_ON(BrowserThread::UI); // Let's not support tab capture for now. - if (request.video_type == content::MEDIA_TAB_VIDEO_CAPTURE || request.audio_type == content::MEDIA_TAB_AUDIO_CAPTURE) { - std::move(callback).Run(content::MediaStreamDevices(), content::MEDIA_DEVICE_NOT_SUPPORTED, std::unique_ptr<content::MediaStreamUI>()); + if (request.video_type == blink::MEDIA_GUM_TAB_VIDEO_CAPTURE || request.audio_type == blink::MEDIA_GUM_TAB_AUDIO_CAPTURE) { + std::move(callback).Run(blink::MediaStreamDevices(), blink::MEDIA_DEVICE_NOT_SUPPORTED, std::unique_ptr<content::MediaStreamUI>()); return; } - if (request.video_type == content::MEDIA_DESKTOP_VIDEO_CAPTURE || request.audio_type == content::MEDIA_DESKTOP_AUDIO_CAPTURE) { + if (request.video_type == blink::MEDIA_GUM_DESKTOP_VIDEO_CAPTURE || request.audio_type == blink::MEDIA_GUM_DESKTOP_AUDIO_CAPTURE) { const bool screenCaptureEnabled = adapterClient->webEngineSettings()->testAttribute(WebEngineSettings::ScreenCaptureEnabled); const bool originIsSecure = content::IsOriginSecure(request.security_origin); if (!screenCaptureEnabled || !originIsSecure) { - std::move(callback).Run(content::MediaStreamDevices(), content::MEDIA_DEVICE_INVALID_STATE, std::unique_ptr<content::MediaStreamUI>()); + std::move(callback).Run(blink::MediaStreamDevices(), blink::MEDIA_DEVICE_INVALID_STATE, std::unique_ptr<content::MediaStreamUI>()); return; } @@ -303,10 +303,10 @@ void MediaCaptureDevicesDispatcher::processMediaAccessRequest(WebContentsAdapter void MediaCaptureDevicesDispatcher::processDesktopCaptureAccessRequest(content::WebContents *webContents, const content::MediaStreamRequest &request, content::MediaResponseCallback callback) { - content::MediaStreamDevices devices; + blink::MediaStreamDevices devices; - if (request.video_type != content::MEDIA_DESKTOP_VIDEO_CAPTURE || request.requested_video_device_id.empty()) { - std::move(callback).Run(devices, content::MEDIA_DEVICE_INVALID_STATE, std::unique_ptr<content::MediaStreamUI>()); + if (request.video_type != blink::MEDIA_GUM_DESKTOP_VIDEO_CAPTURE || request.requested_video_device_id.empty()) { + std::move(callback).Run(devices, blink::MEDIA_DEVICE_INVALID_STATE, std::unique_ptr<content::MediaStreamUI>()); return; } @@ -319,24 +319,24 @@ void MediaCaptureDevicesDispatcher::processDesktopCaptureAccessRequest(content:: // The extension name that the stream is registered with. std::string originalExtensionName; // Resolve DesktopMediaID for the specified device id. - mediaId = getDesktopStreamsRegistry()->RequestMediaForStreamId( + mediaId = content::DesktopStreamsRegistry::GetInstance()->RequestMediaForStreamId( request.requested_video_device_id, main_frame->GetProcess()->GetID(), main_frame->GetRoutingID(), request.security_origin, - &originalExtensionName); + &originalExtensionName, content::kRegistryStreamTypeDesktop); } // Received invalid device id. if (mediaId.type == content::DesktopMediaID::TYPE_NONE) { - std::move(callback).Run(devices, content::MEDIA_DEVICE_INVALID_STATE, std::unique_ptr<content::MediaStreamUI>()); + std::move(callback).Run(devices, blink::MEDIA_DEVICE_INVALID_STATE, std::unique_ptr<content::MediaStreamUI>()); return; } // Audio is only supported for screen capture streams. - bool capture_audio = (mediaId.type == content::DesktopMediaID::TYPE_SCREEN && request.audio_type == content::MEDIA_DESKTOP_AUDIO_CAPTURE); + bool capture_audio = (mediaId.type == content::DesktopMediaID::TYPE_SCREEN && request.audio_type == blink::MEDIA_GUM_DESKTOP_AUDIO_CAPTURE); getDevicesForDesktopCapture(&devices, mediaId, capture_audio); - std::move(callback).Run(devices, devices.empty() ? content::MEDIA_DEVICE_INVALID_STATE : content::MEDIA_DEVICE_OK, + std::move(callback).Run(devices, devices.empty() ? blink::MEDIA_DEVICE_INVALID_STATE : blink::MEDIA_DEVICE_OK, std::unique_ptr<content::MediaStreamUI>()); } @@ -366,14 +366,14 @@ void MediaCaptureDevicesDispatcher::ProcessQueuedAccessRequest(content::WebConte } void MediaCaptureDevicesDispatcher::getDefaultDevices(const std::string &audioDeviceId, const std::string &videoDeviceId, - bool audio, bool video, content::MediaStreamDevices *devices) + bool audio, bool video, blink::MediaStreamDevices *devices) { DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK(audio || video); if (audio) { - const content::MediaStreamDevices &audioDevices = content::MediaCaptureDevices::GetInstance()->GetAudioCaptureDevices(); - const content::MediaStreamDevice *device = findDeviceWithId(audioDevices, audioDeviceId); + const blink::MediaStreamDevices &audioDevices = content::MediaCaptureDevices::GetInstance()->GetAudioCaptureDevices(); + const blink::MediaStreamDevice *device = findDeviceWithId(audioDevices, audioDeviceId); if (!device && !audioDevices.empty()) device = &audioDevices.front(); if (device) @@ -381,8 +381,8 @@ void MediaCaptureDevicesDispatcher::getDefaultDevices(const std::string &audioDe } if (video) { - const content::MediaStreamDevices &videoDevices = content::MediaCaptureDevices::GetInstance()->GetVideoCaptureDevices(); - const content::MediaStreamDevice *device = findDeviceWithId(videoDevices, videoDeviceId); + const blink::MediaStreamDevices &videoDevices = content::MediaCaptureDevices::GetInstance()->GetVideoCaptureDevices(); + const blink::MediaStreamDevice *device = findDeviceWithId(videoDevices, videoDeviceId); if (!device && !videoDevices.empty()) device = &videoDevices.front(); if (device) @@ -390,29 +390,20 @@ void MediaCaptureDevicesDispatcher::getDefaultDevices(const std::string &audioDe } } -DesktopStreamsRegistry *MediaCaptureDevicesDispatcher::getDesktopStreamsRegistry() -{ - if (!m_desktopStreamsRegistry) - m_desktopStreamsRegistry.reset(new DesktopStreamsRegistry()); - return m_desktopStreamsRegistry.get(); -} - -void MediaCaptureDevicesDispatcher::OnMediaRequestStateChanged(int render_process_id, int render_frame_id, int page_request_id, const GURL &security_origin, content::MediaStreamType stream_type, content::MediaRequestState state) +void MediaCaptureDevicesDispatcher::OnMediaRequestStateChanged(int render_process_id, int render_frame_id, int page_request_id, const GURL &security_origin, blink::MediaStreamType stream_type, content::MediaRequestState state) { DCHECK_CURRENTLY_ON(BrowserThread::IO); - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - base::Bind( - &MediaCaptureDevicesDispatcher::updateMediaRequestStateOnUIThread, - base::Unretained(this), render_process_id, render_frame_id, - page_request_id, security_origin, stream_type, state)); + base::PostTaskWithTraits(FROM_HERE, {BrowserThread::UI}, + base::BindOnce(&MediaCaptureDevicesDispatcher::updateMediaRequestStateOnUIThread, + base::Unretained(this), render_process_id, render_frame_id, + page_request_id, security_origin, stream_type, state)); } void MediaCaptureDevicesDispatcher::updateMediaRequestStateOnUIThread(int render_process_id, int render_frame_id, int page_request_id, const GURL & /*security_origin*/, - content::MediaStreamType /*stream_type*/, + blink::MediaStreamType /*stream_type*/, content::MediaRequestState state) { DCHECK_CURRENTLY_ON(BrowserThread::UI); diff --git a/src/core/media_capture_devices_dispatcher.h b/src/core/media_capture_devices_dispatcher.h index 0e5aa38be..07afd54bf 100644 --- a/src/core/media_capture_devices_dispatcher.h +++ b/src/core/media_capture_devices_dispatcher.h @@ -55,9 +55,6 @@ #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" #include "content/public/browser/web_contents_delegate.h" -#include "content/public/common/media_stream_request.h" - -class DesktopStreamsRegistry; namespace QtWebEngineCore { @@ -75,7 +72,7 @@ public: void handleMediaAccessPermissionResponse(content::WebContents *, const QUrl &securityOrigin, WebContentsAdapterClient::MediaRequestFlags); private: - void getDefaultDevices(const std::string &audioDeviceId, const std::string &videoDeviceId, bool audio, bool video, content::MediaStreamDevices *); + void getDefaultDevices(const std::string &audioDeviceId, const std::string &videoDeviceId, bool audio, bool video, blink::MediaStreamDevices *); // Overridden from content::MediaObserver: void OnAudioCaptureDevicesChanged() override {} @@ -84,22 +81,20 @@ private: int render_frame_id, int page_request_id, const GURL &security_origin, - content::MediaStreamType stream_type, + blink::MediaStreamType stream_type, content::MediaRequestState state) override; void OnCreatingAudioStream(int /*render_process_id*/, int /*render_frame_id*/) override {} void OnSetCapturingLinkSecured(int /*render_process_id*/, int /*render_frame_id*/, int /*page_request_id*/, - content::MediaStreamType /*stream_type*/, + blink::MediaStreamType /*stream_type*/, bool /*is_secure*/) override {} - DesktopStreamsRegistry *getDesktopStreamsRegistry(); - friend struct base::DefaultSingletonTraits<MediaCaptureDevicesDispatcher>; - typedef base::RepeatingCallback<void(const content::MediaStreamDevices &devices, - content::MediaStreamRequestResult result, + typedef base::RepeatingCallback<void(const blink::MediaStreamDevices &devices, + blink::MediaStreamRequestResult result, std::unique_ptr<content::MediaStreamUI> ui)> RepeatingMediaResponseCallback; @@ -125,12 +120,11 @@ private: void ProcessQueuedAccessRequest(content::WebContents *); // Called by the MediaObserver() functions, executed on UI thread. - void updateMediaRequestStateOnUIThread(int render_process_id, int render_frame_id, int page_request_id, const GURL &security_origin, content::MediaStreamType stream_type, content::MediaRequestState state); + void updateMediaRequestStateOnUIThread(int render_process_id, int render_frame_id, int page_request_id, const GURL &security_origin, + blink::MediaStreamType stream_type, content::MediaRequestState state); RequestsQueues m_pendingRequests; - std::unique_ptr<DesktopStreamsRegistry> m_desktopStreamsRegistry; - content::NotificationRegistrar m_notificationsRegistrar; DISALLOW_COPY_AND_ASSIGN(MediaCaptureDevicesDispatcher); diff --git a/src/core/net/client_cert_override.cpp b/src/core/net/client_cert_override.cpp new file mode 100644 index 000000000..305f0cef0 --- /dev/null +++ b/src/core/net/client_cert_override.cpp @@ -0,0 +1,176 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "client_cert_override.h" + +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/task/post_task.h" +#include "base/callback_forward.h" +#include "content/public/browser/browser_task_traits.h" +#include "net/ssl/client_cert_store.h" +#include "net/ssl/ssl_cert_request_info.h" +#include "net/ssl/ssl_private_key.h" +#include "net/cert/x509_certificate.h" +#include "third_party/boringssl/src/include/openssl/pem.h" +#include "third_party/boringssl/src/include/openssl/err.h" +#include "third_party/boringssl/src/include/openssl/evp.h" + +#include "client_cert_store_data.h" +#include "profile_io_data_qt.h" + +#include <QtNetwork/qtnetworkglobal.h> + +#if defined(USE_NSS_CERTS) +#include "net/ssl/client_cert_store_nss.h" +#endif + +#if defined(OS_WIN) +#include "net/ssl/client_cert_store_win.h" +#endif + +#if defined(OS_MACOSX) +#include "net/ssl/client_cert_store_mac.h" +#endif + +namespace { + +class ClientCertIdentityOverride : public net::ClientCertIdentity +{ +public: + ClientCertIdentityOverride(scoped_refptr<net::X509Certificate> cert, scoped_refptr<net::SSLPrivateKey> key) + : net::ClientCertIdentity(std::move(cert)), m_key(std::move(key)) {} + ~ClientCertIdentityOverride() override = default; + + void AcquirePrivateKey(const base::Callback<void(scoped_refptr<net::SSLPrivateKey>)> &private_key_callback) override + { + private_key_callback.Run(m_key); + } + +#if defined(OS_MACOSX) + SecIdentityRef sec_identity_ref() const override + { + return nullptr; + } +#endif + +private: + scoped_refptr<net::SSLPrivateKey> m_key; +}; + +} // namespace + +namespace QtWebEngineCore { + +ClientCertOverrideStore::ClientCertOverrideStore(ClientCertificateStoreData *storeData) + : ClientCertStore() + , m_storeData(storeData) + , m_nativeStore(createNativeStore()) +{ +} + +ClientCertOverrideStore::~ClientCertOverrideStore() = default; + +#if QT_CONFIG(ssl) +net::ClientCertIdentityList ClientCertOverrideStore::GetClientCertsOnUIThread(const net::SSLCertRequestInfo &cert_request_info) +{ + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + const auto &clientCertOverrideData = m_storeData->extraCerts; + // Look for certificates in memory store + for (int i = 0; i < clientCertOverrideData.length(); i++) { + scoped_refptr<net::X509Certificate> cert = clientCertOverrideData[i]->certPtr; + if (cert != NULL && cert->IsIssuedByEncoded(cert_request_info.cert_authorities)) { + net::ClientCertIdentityList selected_identities; + selected_identities.push_back(std::make_unique<ClientCertIdentityOverride>(cert, clientCertOverrideData[i]->keyPtr)); + return selected_identities; + } + } + return net::ClientCertIdentityList(); +} + +void ClientCertOverrideStore::GetClientCertsReturn(const net::SSLCertRequestInfo &cert_request_info, + const ClientCertListCallback &callback, + net::ClientCertIdentityList &&result) +{ + // Continue with native cert store if matching certificatse were not found in memory + if (result.empty() && m_nativeStore) + m_nativeStore->GetClientCerts(cert_request_info, callback); + else + callback.Run(std::move(result)); +} + +#endif // QT_CONFIG(ssl) + +void ClientCertOverrideStore::GetClientCerts(const net::SSLCertRequestInfo &cert_request_info, + const ClientCertListCallback &callback) +{ +#if QT_CONFIG(ssl) + // Access the user-provided data from the UI thread, but return on whatever thread this is. + if (base::PostTaskWithTraitsAndReplyWithResult( + FROM_HERE, { content::BrowserThread::UI }, + base::BindOnce(&ClientCertOverrideStore::GetClientCertsOnUIThread, + base::Unretained(this), base::ConstRef(cert_request_info)), + base::BindOnce(&ClientCertOverrideStore::GetClientCertsReturn, + base::Unretained(this), base::ConstRef(cert_request_info), callback)) + ) { + return; + } +#endif // QT_CONFIG(ssl) + + // Continue with native cert store if we failed to post task + if (m_nativeStore) + m_nativeStore->GetClientCerts(cert_request_info, callback); + else + callback.Run(net::ClientCertIdentityList()); +} + +// static +std::unique_ptr<net::ClientCertStore> ClientCertOverrideStore::createNativeStore() +{ +#if defined(USE_NSS_CERTS) + return std::unique_ptr<net::ClientCertStore>(new net::ClientCertStoreNSS(net::ClientCertStoreNSS::PasswordDelegateFactory())); +#elif defined(OS_WIN) + return std::unique_ptr<net::ClientCertStore>(new net::ClientCertStoreWin()); +#elif defined(OS_MACOSX) + return std::unique_ptr<net::ClientCertStore>(new net::ClientCertStoreMac()); +#else + return nullptr; +#endif +} +} // namespace QtWebEngineCore diff --git a/src/core/net/client_cert_override.h b/src/core/net/client_cert_override.h new file mode 100644 index 000000000..35c1f96af --- /dev/null +++ b/src/core/net/client_cert_override.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CLIENT_CERT_OVERRIDE_P_H +#define CLIENT_CERT_OVERRIDE_P_H + +#include "net/ssl/client_cert_store.h" +#include "base/callback_forward.h" +#include "net/cert/x509_certificate.h" + +namespace net { +class SSLCertRequestInfo; +} // namespace net + +namespace QtWebEngineCore { +struct ClientCertificateStoreData; + +class ClientCertOverrideStore : public net::ClientCertStore +{ +public: + ClientCertOverrideStore(ClientCertificateStoreData *storeData); + virtual ~ClientCertOverrideStore() override; + void GetClientCerts(const net::SSLCertRequestInfo &cert_request_info, + const ClientCertListCallback &callback) override; +private: + static std::unique_ptr<net::ClientCertStore> createNativeStore(); + net::ClientCertIdentityList GetClientCertsOnUIThread(const net::SSLCertRequestInfo &request); + void GetClientCertsReturn(const net::SSLCertRequestInfo &cert_request_info, + const ClientCertListCallback &callback, + net::ClientCertIdentityList &&result); + ClientCertificateStoreData *m_storeData; + std::unique_ptr<net::ClientCertStore> m_nativeStore; +}; + +} // QtWebEngineCore + +#endif + + diff --git a/src/core/net/client_cert_store_data.cpp b/src/core/net/client_cert_store_data.cpp new file mode 100644 index 000000000..5a62cb6fe --- /dev/null +++ b/src/core/net/client_cert_store_data.cpp @@ -0,0 +1,168 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "net/client_cert_store_data.h" + +#if QT_CONFIG(ssl) +#include "base/logging.h" +#include "base/macros.h" +#include "base/memory/ptr_util.h" +#include "net/base/net_errors.h" +#include "net/cert/x509_certificate.h" +#include "net/ssl/ssl_platform_key_util.h" +#include "net/ssl/ssl_private_key.h" +#include "net/ssl/threaded_ssl_private_key.h" + +#include "third_party/boringssl/src/include/openssl/ssl.h" +#include "third_party/boringssl/src/include/openssl/digest.h" +#include "third_party/boringssl/src/include/openssl/evp.h" +#include "third_party/boringssl/src/include/openssl/rsa.h" +#include "third_party/boringssl/src/include/openssl/pem.h" + +#include "QtCore/qbytearray.h" + +namespace { + +class SSLPlatformKeyOverride : public net::ThreadedSSLPrivateKey::Delegate { +public: + SSLPlatformKeyOverride(const QByteArray &sslKeyInBytes) + { + m_mem = BIO_new_mem_buf(sslKeyInBytes, -1); + m_key = PEM_read_bio_PrivateKey(m_mem, nullptr, nullptr, nullptr); + } + + ~SSLPlatformKeyOverride() override + { + if (m_key) + EVP_PKEY_free(m_key); + if (m_mem) + BIO_free(m_mem); + } + + net::Error Sign(uint16_t algorithm, base::span<const uint8_t> input, std::vector<uint8_t> *signature) override + { + bssl::ScopedEVP_MD_CTX ctx; + EVP_PKEY_CTX *pctx; + if (!EVP_DigestSignInit(ctx.get(), &pctx, + SSL_get_signature_algorithm_digest(algorithm), + nullptr, m_key)) { + return net::ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED; + } + + if (SSL_is_signature_algorithm_rsa_pss(algorithm)) { + if (!EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) || + !EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, -1 /* hash length */)) { + return net::ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED; + } + } + size_t sig_len = 0; + if (!EVP_DigestSign(ctx.get(), NULL, &sig_len, input.data(), input.size())) + return net::ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED; + signature->resize(sig_len); + if (!EVP_DigestSign(ctx.get(), signature->data(), &sig_len, input.data(), input.size())) + return net::ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED; + signature->resize(sig_len); + return net::OK; + } + + std::vector<uint16_t> GetAlgorithmPreferences() override + { + return { SSL_SIGN_RSA_PKCS1_SHA1, SSL_SIGN_RSA_PKCS1_SHA512 + , SSL_SIGN_RSA_PKCS1_SHA384, SSL_SIGN_RSA_PKCS1_SHA256 }; + } + std::string GetProviderName() override { + return "qtwebengine"; + } +private: + EVP_PKEY *m_key; + BIO *m_mem; + + DISALLOW_COPY_AND_ASSIGN(SSLPlatformKeyOverride); +}; + +scoped_refptr<net::SSLPrivateKey> wrapOpenSSLPrivateKey(const QByteArray &sslKeyInBytes) +{ + if (sslKeyInBytes.isEmpty()) + return nullptr; + + return base::MakeRefCounted<net::ThreadedSSLPrivateKey>( + std::make_unique<SSLPlatformKeyOverride>(sslKeyInBytes), + net::GetSSLPlatformKeyTaskRunner()); +} + +} // namespace + +namespace QtWebEngineCore { + +void ClientCertificateStoreData::add(const QSslCertificate &certificate, const QSslKey &privateKey) +{ + QByteArray sslKeyInBytes = privateKey.toPem(); + QByteArray certInBytes = certificate.toDer(); + + Entry *data = new Entry; + data->keyPtr = wrapOpenSSLPrivateKey(sslKeyInBytes); + data->certPtr = net::X509Certificate::CreateFromBytes(certInBytes.data(), certInBytes.length()); + data->key = privateKey; + data->certificate = certificate; + extraCerts.append(data); +} + +void ClientCertificateStoreData::remove(const QSslCertificate &certificate) +{ + auto it = extraCerts.begin(); + while (it != extraCerts.end()) { + const QtWebEngineCore::ClientCertificateStoreData::Entry *overrideData = *it; + if (certificate.toDer() == overrideData->certificate.toDer()) { + it = extraCerts.erase(it); + delete overrideData; + continue; + } + ++it; + } +} + +void ClientCertificateStoreData::clear() +{ + qDeleteAll(extraCerts); + extraCerts.clear(); +} + +} // namespace QtWebEngineCore + +#endif diff --git a/src/core/net/client_cert_store_data.h b/src/core/net/client_cert_store_data.h new file mode 100644 index 000000000..7f83f4b60 --- /dev/null +++ b/src/core/net/client_cert_store_data.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CLIENT_CERT_STORE_DATA_H +#define CLIENT_CERT_STORE_DATA_H + +#include "qtwebenginecoreglobal.h" +#include "qtnetworkglobal.h" + +#if QT_CONFIG(ssl) +#include "base/memory/ref_counted.h" + +#include <QtCore/qvector.h> +#include <QtNetwork/qsslcertificate.h> +#include <QtNetwork/qsslkey.h> + +namespace net { +class SSLPrivateKey; +class X509Certificate; +} + +namespace QtWebEngineCore { + +struct ClientCertificateStoreData { + struct Entry { + QSslKey key; + QSslCertificate certificate; + scoped_refptr<net::X509Certificate> certPtr; + scoped_refptr<net::SSLPrivateKey> keyPtr; + }; + + void add(const QSslCertificate &certificate, const QSslKey &privateKey); + void remove(const QSslCertificate &certificate); + void clear(); + + QVector<Entry*> extraCerts; +}; + +} // namespace QtWebEngineCore + +#endif +#endif // CLIENT_CERT_STORE_DATA_H diff --git a/src/core/net/cookie_monster_delegate_qt.cpp b/src/core/net/cookie_monster_delegate_qt.cpp index bb89e9e5f..3253b08b9 100644 --- a/src/core/net/cookie_monster_delegate_qt.cpp +++ b/src/core/net/cookie_monster_delegate_qt.cpp @@ -41,6 +41,8 @@ #include "base/bind.h" #include "base/memory/ptr_util.h" +#include "base/task/post_task.h" +#include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "net/cookies/cookie_util.h" @@ -87,8 +89,8 @@ void CookieMonsterDelegateQt::getAllCookies(quint64 callbackId) net::CookieMonster::GetCookieListCallback callback = base::BindOnce(&CookieMonsterDelegateQt::GetAllCookiesCallbackOnIOThread, this, callbackId); - content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, - base::BindOnce(&CookieMonsterDelegateQt::GetAllCookiesOnIOThread, this, std::move(callback))); + base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::IO}, + base::BindOnce(&CookieMonsterDelegateQt::GetAllCookiesOnIOThread, this, std::move(callback))); } void CookieMonsterDelegateQt::GetAllCookiesOnIOThread(net::CookieMonster::GetCookieListCallback callback) @@ -108,9 +110,9 @@ void CookieMonsterDelegateQt::setCookie(quint64 callbackId, const QNetworkCookie GURL gurl = origin.isEmpty() ? sourceUrlForCookie(cookie) : toGurl(origin); - content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, - base::BindOnce(&CookieMonsterDelegateQt::SetCookieOnIOThread, this, - gurl, cookie.toRawForm().toStdString(), std::move(callback))); + base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::IO}, + base::BindOnce(&CookieMonsterDelegateQt::SetCookieOnIOThread, this, + gurl, cookie.toRawForm().toStdString(), std::move(callback))); } void CookieMonsterDelegateQt::SetCookieOnIOThread( @@ -131,9 +133,9 @@ void CookieMonsterDelegateQt::deleteCookie(const QNetworkCookie &cookie, const Q GURL gurl = origin.isEmpty() ? sourceUrlForCookie(cookie) : toGurl(origin); - content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, - base::BindOnce(&CookieMonsterDelegateQt::DeleteCookieOnIOThread, this, - gurl, cookie.name().toStdString())); + base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::IO}, + base::BindOnce(&CookieMonsterDelegateQt::DeleteCookieOnIOThread, this, + gurl, cookie.name().toStdString())); } void CookieMonsterDelegateQt::DeleteCookieOnIOThread(const GURL& url, const std::string& cookie_name) @@ -149,8 +151,8 @@ void CookieMonsterDelegateQt::deleteSessionCookies(quint64 callbackId) net::CookieMonster::DeleteCallback callback = base::BindOnce(&CookieMonsterDelegateQt::DeleteCookiesCallbackOnIOThread, this, callbackId); - content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, - base::BindOnce(&CookieMonsterDelegateQt::DeleteSessionCookiesOnIOThread, this, std::move(callback))); + base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::IO}, + base::BindOnce(&CookieMonsterDelegateQt::DeleteSessionCookiesOnIOThread, this, std::move(callback))); } void CookieMonsterDelegateQt::DeleteSessionCookiesOnIOThread(net::CookieMonster::DeleteCallback callback) @@ -166,8 +168,8 @@ void CookieMonsterDelegateQt::deleteAllCookies(quint64 callbackId) net::CookieMonster::DeleteCallback callback = base::BindOnce(&CookieMonsterDelegateQt::DeleteCookiesCallbackOnIOThread, this, callbackId); - content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, - base::BindOnce(&CookieMonsterDelegateQt::DeleteAllOnIOThread, this, std::move(callback))); + base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::IO}, + base::BindOnce(&CookieMonsterDelegateQt::DeleteAllOnIOThread, this, std::move(callback))); } void CookieMonsterDelegateQt::DeleteAllOnIOThread(net::CookieMonster::DeleteCallback callback) @@ -238,26 +240,23 @@ void CookieMonsterDelegateQt::GetAllCookiesCallbackOnIOThread(qint64 callbackId, for (auto &&cookie : cookies) rawCookies += toQt(cookie).toRawForm() % QByteArrayLiteral("\n"); - content::BrowserThread::PostTask( - content::BrowserThread::UI, - FROM_HERE, - base::BindOnce(&CookieMonsterDelegateQt::GetAllCookiesCallbackOnUIThread, this, callbackId, rawCookies)); + base::PostTaskWithTraits( + FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(&CookieMonsterDelegateQt::GetAllCookiesCallbackOnUIThread, this, callbackId, rawCookies)); } void CookieMonsterDelegateQt::SetCookieCallbackOnIOThread(qint64 callbackId, bool success) { - content::BrowserThread::PostTask( - content::BrowserThread::UI, - FROM_HERE, - base::BindOnce(&CookieMonsterDelegateQt::SetCookieCallbackOnUIThread, this, callbackId, success)); + base::PostTaskWithTraits( + FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(&CookieMonsterDelegateQt::SetCookieCallbackOnUIThread, this, callbackId, success)); } void CookieMonsterDelegateQt::DeleteCookiesCallbackOnIOThread(qint64 callbackId, uint numCookies) { - content::BrowserThread::PostTask( - content::BrowserThread::UI, - FROM_HERE, - base::BindOnce(&CookieMonsterDelegateQt::DeleteCookiesCallbackOnUIThread, this, callbackId, numCookies)); + base::PostTaskWithTraits( + FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(&CookieMonsterDelegateQt::DeleteCookiesCallbackOnUIThread, this, callbackId, numCookies)); } void CookieMonsterDelegateQt::GetAllCookiesCallbackOnUIThread(qint64 callbackId, const QByteArray &cookies) diff --git a/src/core/net/cookie_monster_delegate_qt.h b/src/core/net/cookie_monster_delegate_qt.h index 7933ba329..88e92b560 100644 --- a/src/core/net/cookie_monster_delegate_qt.h +++ b/src/core/net/cookie_monster_delegate_qt.h @@ -75,7 +75,7 @@ namespace QtWebEngineCore { static const char* const kCookieableSchemes[] = { "http", "https", "qrc", "ws", "wss" }; -class QWEBENGINECORE_PRIVATE_EXPORT CookieMonsterDelegateQt : public base::RefCountedThreadSafe<CookieMonsterDelegateQt> { +class Q_WEBENGINECORE_PRIVATE_EXPORT CookieMonsterDelegateQt : public base::RefCountedThreadSafe<CookieMonsterDelegateQt> { QPointer<QWebEngineCookieStore> m_client; net::CookieMonster *m_cookieMonster; std::vector<std::unique_ptr<net::CookieChangeSubscription>> m_subscriptions; diff --git a/src/core/net/custom_protocol_handler.cpp b/src/core/net/custom_protocol_handler.cpp index 5132782c2..7e8ee47ab 100644 --- a/src/core/net/custom_protocol_handler.cpp +++ b/src/core/net/custom_protocol_handler.cpp @@ -54,7 +54,7 @@ CustomProtocolHandler::CustomProtocolHandler(QPointer<ProfileAdapter> profileAda net::URLRequestJob *CustomProtocolHandler::MaybeCreateJob(net::URLRequest *request, net::NetworkDelegate *networkDelegate) const { if (!networkDelegate) - return new net::URLRequestErrorJob(request, Q_NULLPTR, net::ERR_ACCESS_DENIED); + return new net::URLRequestErrorJob(request, nullptr, net::ERR_ACCESS_DENIED); return new URLRequestCustomJob(request, networkDelegate, request->url().scheme(), m_profileAdapter); } diff --git a/src/core/net/custom_protocol_handler.h b/src/core/net/custom_protocol_handler.h index d5b512b03..7b189763c 100644 --- a/src/core/net/custom_protocol_handler.h +++ b/src/core/net/custom_protocol_handler.h @@ -71,7 +71,7 @@ class ProfileAdapter; // Implements a ProtocolHandler for custom URL schemes. // If |network_delegate_| is NULL then all file requests will fail with ERR_ACCESS_DENIED. -class QWEBENGINECORE_PRIVATE_EXPORT CustomProtocolHandler : public net::URLRequestJobFactory::ProtocolHandler { +class Q_WEBENGINECORE_PRIVATE_EXPORT CustomProtocolHandler : public net::URLRequestJobFactory::ProtocolHandler { public: CustomProtocolHandler(QPointer<ProfileAdapter> profileAdapter); diff --git a/src/core/net/network_delegate_qt.cpp b/src/core/net/network_delegate_qt.cpp index f6202cf1b..7f278fd92 100644 --- a/src/core/net/network_delegate_qt.cpp +++ b/src/core/net/network_delegate_qt.cpp @@ -39,22 +39,26 @@ #include "network_delegate_qt.h" -#include "profile_adapter.h" +#include "base/task/post_task.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 "content/public/browser/render_view_host.h" #include "content/public/browser/resource_request_info.h" -#include "cookie_monster_delegate_qt.h" -#include "ui/base/page_transition_types.h" -#include "profile_io_data_qt.h" #include "net/base/load_flags.h" #include "net/url_request/url_request.h" +#include "ui/base/page_transition_types.h" + +#include "profile_adapter.h" +#include "cookie_monster_delegate_qt.h" +#include "profile_io_data_qt.h" #include "qwebengineurlrequestinfo.h" #include "qwebengineurlrequestinfo_p.h" #include "qwebengineurlrequestinterceptor.h" #include "type_conversion.h" #include "web_contents_adapter_client.h" #include "web_contents_view_qt.h" +#include "url_request_notification.h" namespace QtWebEngineCore { @@ -84,128 +88,18 @@ WebContentsAdapterClient::NavigationType pageTransitionToNavigationType(ui::Page } } -namespace { - -QWebEngineUrlRequestInfo::ResourceType toQt(content::ResourceType resourceType) +static QWebEngineUrlRequestInfo::ResourceType toQt(content::ResourceType resourceType) { if (resourceType >= 0 && resourceType < content::ResourceType(QWebEngineUrlRequestInfo::ResourceTypeLast)) return static_cast<QWebEngineUrlRequestInfo::ResourceType>(resourceType); return QWebEngineUrlRequestInfo::ResourceTypeUnknown; } -QWebEngineUrlRequestInfo::NavigationType toQt(WebContentsAdapterClient::NavigationType navigationType) +static QWebEngineUrlRequestInfo::NavigationType toQt(WebContentsAdapterClient::NavigationType navigationType) { return static_cast<QWebEngineUrlRequestInfo::NavigationType>(navigationType); } -// Notifies WebContentsAdapterClient of a new URLRequest. -class URLRequestNotification { -public: - URLRequestNotification(net::URLRequest *request, - const QUrl &url, - bool isMainFrameRequest, - int navigationType, - int frameTreeNodeId, - net::CompletionOnceCallback callback) - : m_request(request) - , m_url(url) - , m_isMainFrameRequest(isMainFrameRequest) - , m_navigationType(navigationType) - , m_frameTreeNodeId(frameTreeNodeId) - , m_callback(std::move(callback)) - { - DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - - m_request->SetUserData(UserData::key, std::make_unique<UserData>(this)); - - content::BrowserThread::PostTask( - content::BrowserThread::UI, - FROM_HERE, - base::Bind(&URLRequestNotification::notify, base::Unretained(this))); - } - -private: - // Calls cancel() when the URLRequest is destroyed. - class UserData : public base::SupportsUserData::Data { - public: - UserData(URLRequestNotification *ptr) : m_ptr(ptr) {} - ~UserData() { m_ptr->cancel(); } - static const char key[]; - private: - URLRequestNotification *m_ptr; - }; - - void cancel() - { - DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - - // May run concurrently with notify() but we only touch m_request here. - - m_request = nullptr; - } - - void notify() - { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - - // May run concurrently with cancel() so no peeking at m_request here. - - int error = net::OK; - content::WebContents *webContents = content::WebContents::FromFrameTreeNodeId(m_frameTreeNodeId); - if (webContents) { - int navigationRequestAction = WebContentsAdapterClient::AcceptRequest; - WebContentsAdapterClient *client = - WebContentsViewQt::from(static_cast<content::WebContentsImpl*>(webContents)->GetView())->client(); - client->navigationRequested(m_navigationType, - m_url, - navigationRequestAction, - m_isMainFrameRequest); - error = net::ERR_FAILED; - switch (static_cast<WebContentsAdapterClient::NavigationRequestAction>(navigationRequestAction)) { - case WebContentsAdapterClient::AcceptRequest: - error = net::OK; - break; - case WebContentsAdapterClient::IgnoreRequest: - error = net::ERR_ABORTED; - break; - } - DCHECK(error != net::ERR_FAILED); - } - - // Run the callback on the IO thread. - content::BrowserThread::PostTask( - content::BrowserThread::IO, - FROM_HERE, - base::BindOnce(&URLRequestNotification::complete, base::Unretained(this), error)); - } - - void complete(int error) - { - DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - - if (m_request) { - if (m_request->status().status() != net::URLRequestStatus::CANCELED) - std::move(m_callback).Run(error); - m_request->RemoveUserData(UserData::key); - } - - delete this; - } - - ~URLRequestNotification() {} - - net::URLRequest *m_request; - QUrl m_url; - bool m_isMainFrameRequest; - int m_navigationType; - int m_frameTreeNodeId; - net::CompletionOnceCallback m_callback; -}; - -const char URLRequestNotification::UserData::key[] = "QtWebEngineCore::URLRequestNotification"; - -} // namespace - NetworkDelegateQt::NetworkDelegateQt(ProfileIODataQt *data) : m_profileIOData(data) { @@ -215,7 +109,6 @@ int NetworkDelegateQt::OnBeforeURLRequest(net::URLRequest *request, net::Complet { Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); Q_ASSERT(m_profileIOData); - const content::ResourceRequestInfo *resourceInfo = content::ResourceRequestInfo::ForRequest(request); content::ResourceType resourceType = content::RESOURCE_TYPE_LAST_TYPE; @@ -234,56 +127,65 @@ int NetworkDelegateQt::OnBeforeURLRequest(net::URLRequest *request, net::Complet else firstPartyUrl = toQt(request->site_for_cookies()); - QWebEngineUrlRequestInterceptor* interceptor = m_profileIOData->acquireInterceptor(); - if (interceptor) { - QWebEngineUrlRequestInfoPrivate *infoPrivate = new QWebEngineUrlRequestInfoPrivate(toQt(resourceType), - toQt(navigationType), - qUrl, - firstPartyUrl, - QByteArray::fromStdString(request->method())); - QWebEngineUrlRequestInfo requestInfo(infoPrivate); - interceptor->interceptRequest(requestInfo); - m_profileIOData->releaseInterceptor(); - if (requestInfo.changed()) { - int result = infoPrivate->shouldBlockRequest ? net::ERR_BLOCKED_BY_CLIENT : net::OK; - - if (qUrl != infoPrivate->url) - *newUrl = toGurl(infoPrivate->url); - - if (!infoPrivate->extraHeaders.isEmpty()) { - auto end = infoPrivate->extraHeaders.constEnd(); - for (auto header = infoPrivate->extraHeaders.constBegin(); header != end; ++header) { - std::string h = header.key().toStdString(); - if (base::LowerCaseEqualsASCII(h, "referer")) { - request->SetReferrer(header.value().toStdString()); - } else { - request->SetExtraRequestHeaderByName(h, header.value().toStdString(), /* overwrite */ true); + QWebEngineUrlRequestInfoPrivate *infoPrivate = new QWebEngineUrlRequestInfoPrivate(toQt(resourceType), + toQt(navigationType), + qUrl, + firstPartyUrl, + QByteArray::fromStdString(request->method())); + QWebEngineUrlRequestInfo requestInfo(infoPrivate); + + // Deprecated =begin + // quick peek if deprecated + QWebEngineUrlRequestInterceptor* profileInterceptor = m_profileIOData->requestInterceptor(); + if (profileInterceptor && profileInterceptor->property("deprecated").toBool()) { + profileInterceptor = nullptr; + if (QWebEngineUrlRequestInterceptor* interceptor = m_profileIOData->acquireInterceptor()) { + interceptor->interceptRequest(requestInfo); + m_profileIOData->releaseInterceptor(); + if (requestInfo.changed()) { + int result = infoPrivate->shouldBlockRequest ? net::ERR_BLOCKED_BY_CLIENT : net::OK; + + if (qUrl != infoPrivate->url) + *newUrl = toGurl(infoPrivate->url); + + if (!infoPrivate->extraHeaders.isEmpty()) { + auto end = infoPrivate->extraHeaders.constEnd(); + for (auto header = infoPrivate->extraHeaders.constBegin(); header != end; ++header) { + std::string h = header.key().toStdString(); + if (base::LowerCaseEqualsASCII(h, "referer")) { + request->SetReferrer(header.value().toStdString()); + } else { + request->SetExtraRequestHeaderByName(h, header.value().toStdString(), /* overwrite */ true); + } } } - } - if (result != net::OK) - return result; + if (result != net::OK) + return result; + + requestInfo.resetChanged(); + } + } else { + m_profileIOData->releaseInterceptor(); } - } else { - m_profileIOData->releaseInterceptor(); } + // Deprecated =cut if (!resourceInfo) return net::OK; - int frameTreeNodeId = resourceInfo->GetFrameTreeNodeId(); - // Only intercept MAIN_FRAME and SUB_FRAME with an associated render frame. - if (!content::IsResourceTypeFrame(resourceType) || frameTreeNodeId == -1) + if (!m_profileIOData->hasPageInterceptors() && !profileInterceptor && !content::IsResourceTypeFrame(resourceType)) return net::OK; + auto webContentsGetter = resourceInfo->GetWebContentsGetterForRequest(); new URLRequestNotification( request, - qUrl, resourceInfo->IsMainFrame(), - navigationType, - frameTreeNodeId, - std::move(callback) + newUrl, + std::move(requestInfo), + webContentsGetter, + std::move(callback), + profileInterceptor ? m_profileIOData->profileAdapter() : nullptr ); // We'll run the callback after we notified the UI thread. @@ -300,19 +202,26 @@ void NetworkDelegateQt::OnCompleted(net::URLRequest */*request*/, bool /*started bool NetworkDelegateQt::OnCanSetCookie(const net::URLRequest& request, const net::CanonicalCookie & /*cookie*/, - net::CookieOptions*) + net::CookieOptions*, + bool allowedFromCaller) { + if (!allowedFromCaller) + return false; return canSetCookies(request.site_for_cookies(), request.url(), std::string()); } -bool NetworkDelegateQt::OnCanGetCookies(const net::URLRequest& request, const net::CookieList&) +bool NetworkDelegateQt::OnCanGetCookies(const net::URLRequest& request, const net::CookieList&, bool allowedFromCaller) { + if (!allowedFromCaller) + return false; return canGetCookies(request.site_for_cookies(), request.url()); } -bool NetworkDelegateQt::OnCanEnablePrivacyMode(const GURL &url, const GURL &site_for_cookies) const +bool NetworkDelegateQt::OnForcePrivacyMode(const GURL &url, const GURL &site_for_cookies) const { - return !canGetCookies(site_for_cookies, url); + return false; +// FIXME: This is what the NetworkContext implementation does (changes tst_QWebEngineCookieStore tests since 72) +// return !canGetCookies(site_for_cookies, url); } bool NetworkDelegateQt::canSetCookies(const GURL &first_party, const GURL &url, const std::string &cookie_line) const @@ -376,11 +285,6 @@ bool NetworkDelegateQt::OnCanAccessFile(const net::URLRequest&, const base::File return true; } -bool NetworkDelegateQt::OnAreExperimentalCookieFeaturesEnabled() const -{ - return false; -} - bool NetworkDelegateQt::OnCancelURLRequestWithPolicyViolatingReferrerHeader(const net::URLRequest&, const GURL&, const GURL&) const { return false; diff --git a/src/core/net/network_delegate_qt.h b/src/core/net/network_delegate_qt.h index e4ff196aa..53debadcd 100644 --- a/src/core/net/network_delegate_qt.h +++ b/src/core/net/network_delegate_qt.h @@ -62,7 +62,7 @@ public: // net::NetworkDelegate implementation int OnBeforeURLRequest(net::URLRequest* request, net::CompletionOnceCallback callback, GURL* new_url) override; void OnURLRequestDestroyed(net::URLRequest* request) override; - bool OnCanSetCookie(const net::URLRequest& request, const net::CanonicalCookie& cookie, net::CookieOptions* options) override; + bool OnCanSetCookie(const net::URLRequest& request, const net::CanonicalCookie& cookie, net::CookieOptions* options, bool) override; int OnBeforeStartTransaction(net::URLRequest *request, const net::CompletionOnceCallback callback, net::HttpRequestHeaders *headers) override; void OnBeforeSendHeaders(net::URLRequest* request, const net::ProxyInfo& proxy_info, const net::ProxyRetryInfoMap& proxy_retry_info, net::HttpRequestHeaders* headers) override; @@ -75,10 +75,9 @@ public: void OnCompleted(net::URLRequest *request, bool started, int net_error) override; void OnPACScriptError(int, const base::string16&) override; net::NetworkDelegate::AuthRequiredResponse OnAuthRequired(net::URLRequest*, const net::AuthChallengeInfo&, AuthCallback, net::AuthCredentials*) override; - bool OnCanGetCookies(const net::URLRequest&, const net::CookieList&) override; + bool OnCanGetCookies(const net::URLRequest&, const net::CookieList&, bool) override; bool OnCanAccessFile(const net::URLRequest&, const base::FilePath&, const base::FilePath&) const override; - bool OnCanEnablePrivacyMode(const GURL&, const GURL&) const override; - bool OnAreExperimentalCookieFeaturesEnabled() const override; + bool OnForcePrivacyMode(const GURL&, const GURL&) const override; bool OnCancelURLRequestWithPolicyViolatingReferrerHeader(const net::URLRequest&, const GURL&, const GURL&) const override; bool OnCanQueueReportingReport(const url::Origin& origin) const override; diff --git a/src/core/net/proxy_config_service_qt.cpp b/src/core/net/proxy_config_service_qt.cpp index 13b969281..00ff1c54d 100644 --- a/src/core/net/proxy_config_service_qt.cpp +++ b/src/core/net/proxy_config_service_qt.cpp @@ -47,6 +47,7 @@ #include "base/bind.h" #include "content/public/browser/browser_thread.h" +#include "components/proxy_config/pref_proxy_config_tracker_impl.h" using content::BrowserThread; @@ -68,10 +69,13 @@ net::ProxyServer ProxyConfigServiceQt::fromQNetworkProxy(const QNetworkProxy &qt } } -ProxyConfigServiceQt::ProxyConfigServiceQt(std::unique_ptr<ProxyConfigService> baseService) +ProxyConfigServiceQt::ProxyConfigServiceQt(std::unique_ptr<ProxyConfigService> baseService, + const net::ProxyConfigWithAnnotation& initialConfig, ProxyPrefs::ConfigState initialState) : m_baseService(baseService.release()), m_usesSystemConfiguration(false), - m_registeredObserver(false) + m_registeredObserver(false), + m_prefConfig(initialConfig), + m_perfState(initialState) { } @@ -100,8 +104,10 @@ net::ProxyConfigService::ConfigAvailability ProxyConfigServiceQt::GetLatestProxy ConfigAvailability systemAvailability = net::ProxyConfigService::CONFIG_UNSET; if (m_baseService.get()) systemAvailability = m_baseService->GetLatestProxyConfig(&systemConfig); - *config = systemConfig; - // make sure to get updates via OnProxyConfigChanged + ProxyPrefs::ConfigState configState; + systemAvailability = PrefProxyConfigTrackerImpl::GetEffectiveProxyConfig( + m_perfState, m_prefConfig, systemAvailability, systemConfig, + false, &configState, config); RegisterObserver(); return systemAvailability; } @@ -137,7 +143,7 @@ net::ProxyConfigService::ConfigAvailability ProxyConfigServiceQt::GetLatestProxy qtRules.type = net::ProxyConfig::ProxyRules::Type::EMPTY; } - qtRules.bypass_rules.AddRuleToBypassLocal(); // don't use proxy for connections to localhost + qtRules.bypass_rules.PrependRuleToBypassSimpleHostnames(); // don't use proxy for connections to localhost m_qtProxyConfig.proxy_rules() = qtRules; *config = net::ProxyConfigWithAnnotation(m_qtProxyConfig, config->traffic_annotation()); return CONFIG_VALID; diff --git a/src/core/net/proxy_config_service_qt.h b/src/core/net/proxy_config_service_qt.h index dcd303894..09e88d445 100644 --- a/src/core/net/proxy_config_service_qt.h +++ b/src/core/net/proxy_config_service_qt.h @@ -43,8 +43,10 @@ #include "base/memory/ref_counted.h" #include "base/observer_list.h" +#include "net/proxy_resolution/proxy_config.h" #include "net/proxy_resolution/proxy_config_service.h" #include "net/proxy_resolution/proxy_config_with_annotation.h" +#include "components/proxy_config/proxy_prefs.h" #include <QNetworkProxy> @@ -55,7 +57,9 @@ public: static net::ProxyServer fromQNetworkProxy(const QNetworkProxy &); - explicit ProxyConfigServiceQt(std::unique_ptr<ProxyConfigService> baseService); + explicit ProxyConfigServiceQt(std::unique_ptr<ProxyConfigService> baseService, + const net::ProxyConfigWithAnnotation& initialConfig, + ProxyPrefs::ConfigState initialState); ~ProxyConfigServiceQt() override; // ProxyConfigService implementation: @@ -76,7 +80,7 @@ private: void RegisterObserver(); std::unique_ptr<net::ProxyConfigService> m_baseService; - base::ObserverList<net::ProxyConfigService::Observer, true> m_observers; + base::ObserverList<net::ProxyConfigService::Observer, true>::Unchecked m_observers; // Keep the last state around. bool m_usesSystemConfiguration; @@ -86,6 +90,10 @@ private: // Indicates whether the base service registration is done. bool m_registeredObserver; + // Configuration as defined by prefs. + net::ProxyConfigWithAnnotation m_prefConfig; + ProxyPrefs::ConfigState m_perfState; + DISALLOW_COPY_AND_ASSIGN(ProxyConfigServiceQt); }; diff --git a/src/core/net/url_request_qrc_job_qt.h b/src/core/net/qrc_url_scheme_handler.cpp index 11c130693..73bf24f1d 100644 --- a/src/core/net/url_request_qrc_job_qt.h +++ b/src/core/net/qrc_url_scheme_handler.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtWebEngine module of the Qt Toolkit. @@ -37,40 +37,37 @@ ** ****************************************************************************/ -#ifndef URL_REQUEST_QRC_JOB_QT_H_ -#define URL_REQUEST_QRC_JOB_QT_H_ +#include "qrc_url_scheme_handler.h" -#include "net/url_request/url_request.h" -#include "net/url_request/url_request_job.h" +#include <QtWebEngineCore/qwebengineurlrequestjob.h> #include <QFile> +#include <QFileInfo> +#include <QMimeDatabase> +#include <QMimeType> namespace QtWebEngineCore { -// A request job that handles reading qrc file URLs -class URLRequestQrcJobQt : public net::URLRequestJob { +void QrcUrlSchemeHandler::requestStarted(QWebEngineUrlRequestJob *job) +{ + QByteArray requestMethod = job->requestMethod(); + if (requestMethod != "GET") { + job->fail(QWebEngineUrlRequestJob::RequestDenied); + return; + } -public: - URLRequestQrcJobQt(net::URLRequest *request, net::NetworkDelegate *networkDelegate); - void Start() override; - void Kill() override; - int ReadRawData(net::IOBuffer* buf, int buf_size) override;; - bool GetMimeType(std::string *mimeType) const override; - -protected: - virtual ~URLRequestQrcJobQt(); - // Get file mime type and try open file on a background thread. - void startGetHead(); - -private: - qint64 m_remainingBytes; - QFile m_file; - std::string m_mimeType; - base::WeakPtrFactory<URLRequestQrcJobQt> m_weakFactory; - - DISALLOW_COPY_AND_ASSIGN(URLRequestQrcJobQt); -}; + QUrl requestUrl = job->requestUrl(); + QString requestPath = requestUrl.path(); + QScopedPointer<QFile> file(new QFile(':' + requestPath, job)); + if (!file->exists() || file->size() == 0) { + qWarning("QResource '%s' not found or is empty", qUtf8Printable(requestPath)); + job->fail(QWebEngineUrlRequestJob::UrlNotFound); + return; + } + QFileInfo fileInfo(*file); + QMimeDatabase mimeDatabase; + QMimeType mimeType = mimeDatabase.mimeTypeForFile(fileInfo); + job->reply(mimeType.name().toUtf8(), file.take()); +} } // namespace QtWebEngineCore - -#endif // URL_REQUEST_QRC_JOB_QT_H_ diff --git a/src/core/net/qrc_url_scheme_handler.h b/src/core/net/qrc_url_scheme_handler.h new file mode 100644 index 000000000..f6ca92879 --- /dev/null +++ b/src/core/net/qrc_url_scheme_handler.h @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QRC_URL_SCHEME_HANDLER_H +#define QRC_URL_SCHEME_HANDLER_H + +#include <QtWebEngineCore/private/qtwebenginecoreglobal_p.h> +#include <QtWebEngineCore/qwebengineurlschemehandler.h> + +namespace QtWebEngineCore { + +class QrcUrlSchemeHandler final : public QWebEngineUrlSchemeHandler { +public: + void requestStarted(QWebEngineUrlRequestJob *) override; +}; + +} // namespace QtWebEngineCore + +#endif // !QRC_URL_SCHEME_HANDLER_H diff --git a/src/core/net/url_request_context_getter_qt.cpp b/src/core/net/url_request_context_getter_qt.cpp index 636d27358..6081a5e9f 100644 --- a/src/core/net/url_request_context_getter_qt.cpp +++ b/src/core/net/url_request_context_getter_qt.cpp @@ -40,6 +40,10 @@ #include "url_request_context_getter_qt.h" #include "profile_io_data_qt.h" +#include "base/task/post_task.h" +#include "content/public/browser/browser_task_traits.h" +#include "content/public/browser/browser_thread.h" + namespace QtWebEngineCore { URLRequestContextGetterQt::URLRequestContextGetterQt(ProfileIODataQt *data) @@ -59,7 +63,7 @@ net::URLRequestContext *URLRequestContextGetterQt::GetURLRequestContext() scoped_refptr<base::SingleThreadTaskRunner> URLRequestContextGetterQt::GetNetworkTaskRunner() const { - return content::BrowserThread::GetTaskRunnerForThread(content::BrowserThread::IO); + return base::CreateSingleThreadTaskRunnerWithTraits({content::BrowserThread::IO}); } } // namespace QtWebEngineCore diff --git a/src/core/net/url_request_custom_job.cpp b/src/core/net/url_request_custom_job.cpp index d371c7bff..cba9b4dc5 100644 --- a/src/core/net/url_request_custom_job.cpp +++ b/src/core/net/url_request_custom_job.cpp @@ -39,6 +39,9 @@ #include "url_request_custom_job.h" #include "url_request_custom_job_proxy.h" + +#include "base/task/post_task.h" +#include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "net/base/io_buffer.h" @@ -68,17 +71,30 @@ URLRequestCustomJob::~URLRequestCustomJob() if (m_device && m_device->isOpen()) m_device->close(); m_device = nullptr; - content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, - base::Bind(&URLRequestCustomJobProxy::release, - m_proxy)); + base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(&URLRequestCustomJobProxy::release, m_proxy)); } void URLRequestCustomJob::Start() { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, - base::Bind(&URLRequestCustomJobProxy::initialize, - m_proxy, request()->url(), request()->method(), request()->initiator())); + HttpRequestHeaders requestHeaders = request()->extra_request_headers(); + std::map<std::string, std::string> headers; + net::HttpRequestHeaders::Iterator it(requestHeaders); + while (it.GetNext()) + headers.emplace(it.name(), it.value()); + if (!request()->referrer().empty()) + headers.emplace("Referer", request()->referrer()); + + // TODO: handle UploadDataStream, for instance using a QIODevice wrapper. + + base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(&URLRequestCustomJobProxy::initialize, + m_proxy, + request()->url(), + request()->method(), + request()->initiator(), + std::move(headers))); } void URLRequestCustomJob::Kill() @@ -94,9 +110,9 @@ void URLRequestCustomJob::Kill() m_pendingReadPos = 0; } m_device = nullptr; - content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, - base::Bind(&URLRequestCustomJobProxy::release, - m_proxy)); + base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(&URLRequestCustomJobProxy::release, + m_proxy)); URLRequestJob::Kill(); } diff --git a/src/core/net/url_request_custom_job_delegate.cpp b/src/core/net/url_request_custom_job_delegate.cpp index 338bd7137..b5a7a55a7 100644 --- a/src/core/net/url_request_custom_job_delegate.cpp +++ b/src/core/net/url_request_custom_job_delegate.cpp @@ -40,9 +40,12 @@ #include "url_request_custom_job_delegate.h" #include "url_request_custom_job_proxy.h" -#include "type_conversion.h" -#include "net/base/net_errors.h" +#include "base/task/post_task.h" +#include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" +#include "net/base/net_errors.h" + +#include "type_conversion.h" #include <QByteArray> @@ -51,11 +54,13 @@ namespace QtWebEngineCore { URLRequestCustomJobDelegate::URLRequestCustomJobDelegate(URLRequestCustomJobProxy *proxy, const QUrl &url, const QByteArray &method, - const QUrl &initiatorOrigin) + const QUrl &initiatorOrigin, + const QMap<QByteArray, QByteArray> &headers) : m_proxy(proxy), m_request(url), m_method(method), - m_initiatorOrigin(initiatorOrigin) + m_initiatorOrigin(initiatorOrigin), + m_requestHeaders(headers) { } @@ -78,32 +83,36 @@ QUrl URLRequestCustomJobDelegate::initiator() const return m_initiatorOrigin; } +QMap<QByteArray, QByteArray> URLRequestCustomJobDelegate::requestHeaders() const +{ + return m_requestHeaders; +} + void URLRequestCustomJobDelegate::reply(const QByteArray &contentType, QIODevice *device) { if (device) QObject::connect(device, &QIODevice::readyRead, this, &URLRequestCustomJobDelegate::slotReadyRead); - content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, - base::Bind(&URLRequestCustomJobProxy::reply, - m_proxy,contentType.toStdString(),device)); + base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::IO}, + base::BindOnce(&URLRequestCustomJobProxy::reply, + m_proxy,contentType.toStdString(),device)); } void URLRequestCustomJobDelegate::slotReadyRead() { - content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, - base::Bind(&URLRequestCustomJobProxy::readyRead, m_proxy)); + base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::IO}, + base::BindOnce(&URLRequestCustomJobProxy::readyRead, m_proxy)); } void URLRequestCustomJobDelegate::abort() { - content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, - base::Bind(&URLRequestCustomJobProxy::abort, m_proxy)); + base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::IO}, + base::BindOnce(&URLRequestCustomJobProxy::abort, m_proxy)); } void URLRequestCustomJobDelegate::redirect(const QUrl &url) { - content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, - base::Bind(&URLRequestCustomJobProxy::redirect, - m_proxy, toGurl(url))); + base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::IO}, + base::BindOnce(&URLRequestCustomJobProxy::redirect, m_proxy, toGurl(url))); } void URLRequestCustomJobDelegate::fail(Error error) @@ -129,9 +138,8 @@ void URLRequestCustomJobDelegate::fail(Error error) break; } if (net_error) { - content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, - base::Bind(&URLRequestCustomJobProxy::fail, - m_proxy, net_error)); + base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::IO}, + base::BindOnce(&URLRequestCustomJobProxy::fail, m_proxy, net_error)); } } diff --git a/src/core/net/url_request_custom_job_delegate.h b/src/core/net/url_request_custom_job_delegate.h index caabfcf99..0ab1a82c7 100644 --- a/src/core/net/url_request_custom_job_delegate.h +++ b/src/core/net/url_request_custom_job_delegate.h @@ -54,6 +54,7 @@ #include "base/memory/ref_counted.h" #include "qtwebenginecoreglobal_p.h" +#include <QMap> #include <QObject> #include <QUrl> @@ -63,7 +64,7 @@ namespace QtWebEngineCore { class URLRequestCustomJobProxy; -class QWEBENGINECORE_PRIVATE_EXPORT URLRequestCustomJobDelegate : public QObject { +class Q_WEBENGINECORE_PRIVATE_EXPORT URLRequestCustomJobDelegate : public QObject { Q_OBJECT public: ~URLRequestCustomJobDelegate(); @@ -80,6 +81,7 @@ public: QUrl url() const; QByteArray method() const; QUrl initiator() const; + QMap<QByteArray, QByteArray> requestHeaders() const; void reply(const QByteArray &contentType, QIODevice *device); void redirect(const QUrl& url); @@ -93,13 +95,15 @@ private: URLRequestCustomJobDelegate(URLRequestCustomJobProxy *proxy, const QUrl &url, const QByteArray &method, - const QUrl &initiatorOrigin); + const QUrl &initiatorOrigin, + const QMap<QByteArray, QByteArray> &requestHeaders); friend class URLRequestCustomJobProxy; scoped_refptr<URLRequestCustomJobProxy> m_proxy; QUrl m_request; QByteArray m_method; QUrl m_initiatorOrigin; + const QMap<QByteArray, QByteArray> m_requestHeaders; }; } // namespace diff --git a/src/core/net/url_request_custom_job_proxy.cpp b/src/core/net/url_request_custom_job_proxy.cpp index b5f10388c..72d14450e 100644 --- a/src/core/net/url_request_custom_job_proxy.cpp +++ b/src/core/net/url_request_custom_job_proxy.cpp @@ -152,7 +152,9 @@ void URLRequestCustomJobProxy::readyRead() m_job->notifyReadyRead(); } -void URLRequestCustomJobProxy::initialize(GURL url, std::string method, base::Optional<url::Origin> initiator) +void URLRequestCustomJobProxy::initialize(GURL url, std::string method, + base::Optional<url::Origin> initiator, + std::map<std::string, std::string> headers) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); Q_ASSERT(!m_delegate); @@ -164,12 +166,16 @@ void URLRequestCustomJobProxy::initialize(GURL url, std::string method, base::Op QWebEngineUrlSchemeHandler *schemeHandler = nullptr; if (m_profileAdapter) - schemeHandler = m_profileAdapter->customUrlSchemeHandlers()[toQByteArray(m_scheme)]; + schemeHandler = m_profileAdapter->urlSchemeHandler(toQByteArray(m_scheme)); + QMap<QByteArray, QByteArray> qHeaders; + for (auto it = headers.cbegin(); it != headers.cend(); ++it) + qHeaders.insert(toQByteArray(it->first), toQByteArray(it->second)); if (schemeHandler) { m_delegate = new URLRequestCustomJobDelegate(this, toQt(url), QByteArray::fromStdString(method), - initiatorOrigin); + initiatorOrigin, + qHeaders); QWebEngineUrlRequestJob *requestJob = new QWebEngineUrlRequestJob(m_delegate); schemeHandler->requestStarted(requestJob); } diff --git a/src/core/net/url_request_custom_job_proxy.h b/src/core/net/url_request_custom_job_proxy.h index 3986fe119..aa55db07c 100644 --- a/src/core/net/url_request_custom_job_proxy.h +++ b/src/core/net/url_request_custom_job_proxy.h @@ -72,7 +72,7 @@ public: void abort(); void fail(int error); void release(); - void initialize(GURL url, std::string method, base::Optional<url::Origin> initiatorOrigin); + void initialize(GURL url, std::string method, base::Optional<url::Origin> initiatorOrigin, std::map<std::string, std::string> headers); void readyRead(); // IO thread owned: diff --git a/src/core/net/url_request_notification.cpp b/src/core/net/url_request_notification.cpp new file mode 100644 index 000000000..e37ad35bc --- /dev/null +++ b/src/core/net/url_request_notification.cpp @@ -0,0 +1,194 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "url_request_notification.h" + +#include "base/supports_user_data.h" +#include "base/task/post_task.h" +#include "content/browser/web_contents/web_contents_impl.h" +#include "content/public/browser/browser_thread.h" +#include "net/url_request/url_request.h" +#include "web_contents_adapter_client.h" +#include "web_contents_view_qt.h" +#include "profile_io_data_qt.h" +#include "qwebengineurlrequestinfo_p.h" +#include "type_conversion.h" + +namespace QtWebEngineCore { + +// Calls cancel() when the URLRequest is destroyed. +class UserData : public base::SupportsUserData::Data { +public: + UserData(URLRequestNotification *ptr) : m_ptr(ptr) {} + ~UserData() { m_ptr->cancel(); } + static const char key[]; +private: + URLRequestNotification *m_ptr; +}; + +const char UserData::key[] = "QtWebEngineCore::URLRequestNotification"; + +static content::ResourceType fromQt(QWebEngineUrlRequestInfo::ResourceType resourceType) +{ + return static_cast<content::ResourceType>(resourceType); +} + +URLRequestNotification::URLRequestNotification(net::URLRequest *request, + bool isMainFrameRequest, + GURL *newUrl, + QWebEngineUrlRequestInfo &&requestInfo, + content::ResourceRequestInfo::WebContentsGetter webContentsGetter, + net::CompletionOnceCallback callback, + QPointer<ProfileAdapter> adapter) + : m_request(request) + , m_isMainFrameRequest(isMainFrameRequest) + , m_newUrl(newUrl) + , m_originalUrl(requestInfo.requestUrl()) + , m_requestInfo(std::move(requestInfo)) + , m_webContentsGetter(webContentsGetter) + , m_callback(std::move(callback)) + , m_profileAdapter(adapter) +{ + DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + + m_request->SetUserData(UserData::key, std::make_unique<UserData>(this)); + + base::PostTaskWithTraits( + FROM_HERE, + {content::BrowserThread::UI}, + base::BindOnce(&URLRequestNotification::notify, base::Unretained(this))); +} + + +void URLRequestNotification::notify() +{ + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + + // May run concurrently with cancel() so no peeking at m_request here. + + int result = net::OK; + content::WebContents *webContents = m_webContentsGetter.Run(); + + if (webContents) { + + if (m_profileAdapter) { + QWebEngineUrlRequestInterceptor* interceptor = m_profileAdapter->requestInterceptor(); + if (!interceptor->property("deprecated").toBool()) + interceptor->interceptRequest(m_requestInfo); + } + + WebContentsAdapterClient *client = + WebContentsViewQt::from(static_cast<content::WebContentsImpl*>(webContents)->GetView())->client(); + + if (!m_requestInfo.changed()) { + client->interceptRequest(m_requestInfo); + } + + if (m_requestInfo.changed()) { + result = m_requestInfo.d_ptr->shouldBlockRequest ? net::ERR_BLOCKED_BY_CLIENT : net::OK; + // We handle the rest of the changes later when we are back in I/O thread + } + + // Only do navigationRequested on MAIN_FRAME and SUB_FRAME resources + if (result == net::OK && content::IsResourceTypeFrame(fromQt(m_requestInfo.resourceType()))) { + int navigationRequestAction = WebContentsAdapterClient::AcceptRequest; + client->navigationRequested(m_requestInfo.navigationType(), + m_requestInfo.requestUrl(), + navigationRequestAction, + m_isMainFrameRequest); + result = net::ERR_FAILED; + switch (static_cast<WebContentsAdapterClient::NavigationRequestAction>(navigationRequestAction)) { + case WebContentsAdapterClient::AcceptRequest: + result = net::OK; + break; + case WebContentsAdapterClient::IgnoreRequest: + result = net::ERR_ABORTED; + break; + } + DCHECK(result != net::ERR_FAILED); + } + } + + // Run the callback on the IO thread. + base::PostTaskWithTraits( + FROM_HERE, + {content::BrowserThread::IO}, + base::BindOnce(&URLRequestNotification::complete, base::Unretained(this), result)); +} + +void URLRequestNotification::cancel() +{ + DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + + // May run concurrently with notify() but we only touch m_request here. + + m_request = nullptr; +} + +void URLRequestNotification::complete(int error) +{ + DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + + if (m_request) { + if (m_requestInfo.changed()) { + if (m_originalUrl != m_requestInfo.d_ptr->url) + *m_newUrl = toGurl(m_requestInfo.d_ptr->url); + + if (!m_requestInfo.d_ptr->extraHeaders.isEmpty()) { + auto end = m_requestInfo.d_ptr->extraHeaders.constEnd(); + for (auto header = m_requestInfo.d_ptr->extraHeaders.constBegin(); header != end; ++header) { + std::string h = header.key().toStdString(); + if (base::LowerCaseEqualsASCII(h, "referer")) { + m_request->SetReferrer(header.value().toStdString()); + } else { + m_request->SetExtraRequestHeaderByName(h, header.value().toStdString(), /* overwrite */ true); + } + } + } + } + + if (m_request->status().status() != net::URLRequestStatus::CANCELED) + std::move(m_callback).Run(error); + m_request->RemoveUserData(UserData::key); + } + + delete this; +} + +} diff --git a/src/core/net/url_request_notification.h b/src/core/net/url_request_notification.h new file mode 100644 index 000000000..1d9acf12f --- /dev/null +++ b/src/core/net/url_request_notification.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef URL_REQUEST_NOTIFIACTION_H +#define URL_REQUEST_NOTIFIACTION_H + +#include "content/public/browser/resource_request_info.h" +#include "net/base/completion_once_callback.h" +#include "qwebengineurlrequestinfo.h" +#include <QPointer> + +class GURL; + +namespace net { +class URLRequest; +} + +namespace QtWebEngineCore { + +class ProfileAdapter; +class ProfileIoDataQt; + +// Notifies WebContentsAdapterClient of a new URLRequest. +class URLRequestNotification { +public: + URLRequestNotification(net::URLRequest *request, + bool isMainFrameRequest, + GURL *newUrl, + QWebEngineUrlRequestInfo &&requestInfo, + content::ResourceRequestInfo::WebContentsGetter webContentsGetter, + net::CompletionOnceCallback callback, + QPointer<ProfileAdapter> adapter); + ~URLRequestNotification() = default; + void cancel(); + void notify(); + void complete(int error); + +private: + net::URLRequest *m_request; //used only by io thread + bool m_isMainFrameRequest; + GURL *m_newUrl; + const QUrl m_originalUrl; + QWebEngineUrlRequestInfo m_requestInfo; + content::ResourceRequestInfo::WebContentsGetter m_webContentsGetter; + net::CompletionOnceCallback m_callback; + QPointer<ProfileAdapter> m_profileAdapter; +}; +} +#endif diff --git a/src/core/net/url_request_qrc_job_qt.cpp b/src/core/net/url_request_qrc_job_qt.cpp deleted file mode 100644 index 4ac45e7c8..000000000 --- a/src/core/net/url_request_qrc_job_qt.cpp +++ /dev/null @@ -1,133 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtWebEngine module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "url_request_qrc_job_qt.h" - -#include "type_conversion.h" - -#include "base/pending_task.h" -#include "base/threading/thread_task_runner_handle.h" -#include "net/base/net_errors.h" -#include "net/base/io_buffer.h" - -#include <QUrl> -#include <QFileInfo> -#include <QMimeDatabase> -#include <QMimeType> - -using namespace net; -namespace QtWebEngineCore { - -URLRequestQrcJobQt::URLRequestQrcJobQt(URLRequest *request, NetworkDelegate *networkDelegate) - : URLRequestJob(request, networkDelegate) - , m_remainingBytes(0) - , m_weakFactory(this) -{ -} - -URLRequestQrcJobQt::~URLRequestQrcJobQt() -{ - if (m_file.isOpen()) - m_file.close(); -} - -void URLRequestQrcJobQt::Start() -{ - base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, base::Bind(&URLRequestQrcJobQt::startGetHead, m_weakFactory.GetWeakPtr())); -} - -void URLRequestQrcJobQt::Kill() -{ - if (m_file.isOpen()) - m_file.close(); - m_weakFactory.InvalidateWeakPtrs(); - - URLRequestJob::Kill(); -} - -bool URLRequestQrcJobQt::GetMimeType(std::string *mimeType) const -{ - DCHECK(request_); - if (m_mimeType.size() > 0) { - *mimeType = m_mimeType; - return true; - } - return false; -} - -int URLRequestQrcJobQt::ReadRawData(IOBuffer *buf, int bufSize) -{ - DCHECK_GE(m_remainingBytes, 0); - // File has been read finished. - if (!m_remainingBytes || !bufSize) { - return 0; - } - if (m_remainingBytes < bufSize) - bufSize = static_cast<int>(m_remainingBytes); - qint64 rv = m_file.read(buf->data(), bufSize); - if (rv >= 0) { - m_remainingBytes -= rv; - DCHECK_GE(m_remainingBytes, 0); - return static_cast<int>(rv); - } - return static_cast<int>(rv); -} - -void URLRequestQrcJobQt::startGetHead() -{ - // Get qrc file path. - QString qrcFilePath = ':' + toQt(request_->url()).path(); - m_file.setFileName(qrcFilePath); - QFileInfo qrcFileInfo(m_file); - // Get qrc file mime type. - QMimeDatabase mimeDatabase; - QMimeType mimeType = mimeDatabase.mimeTypeForFile(qrcFileInfo); - m_mimeType = mimeType.name().toStdString(); - // Open file - if (m_file.open(QIODevice::ReadOnly) && m_file.size() > 0) { - m_remainingBytes = m_file.size(); - set_expected_content_size(m_remainingBytes); - // Notify that the headers are complete - NotifyHeadersComplete(); - return; - } - qWarning("Resource %s not found or is empty", qUtf8Printable(qrcFilePath)); - NotifyStartError(URLRequestStatus(URLRequestStatus::FAILED, ERR_INVALID_URL)); -} -} // namespace QtWebEngineCore diff --git a/src/core/net/webui_controller_factory_qt.cpp b/src/core/net/webui_controller_factory_qt.cpp index 918500b58..ec36e70d9 100644 --- a/src/core/net/webui_controller_factory_qt.cpp +++ b/src/core/net/webui_controller_factory_qt.cpp @@ -48,6 +48,7 @@ #include "base/location.h" #include "base/threading/thread_task_runner_handle.h" #include "build/build_config.h" +#include "chrome/browser/accessibility/accessibility_ui.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/webui/devtools_ui.h" #include "chrome/browser/ui/webui/quota_internals/quota_internals_ui.h" @@ -136,6 +137,8 @@ WebUIFactoryFunction GetWebUIFactoryFunction(WebUI *web_ui, Profile *profile, co // return nullptr; return &NewWebUI<DevToolsUI>; } + if (url.host() == chrome::kChromeUIAccessibilityHost) + return &NewWebUI<AccessibilityUI>; // if (url.host_piece() == chrome::kChromeUIUserActionsHost) // return &NewWebUI<UserActionsUI>; diff --git a/src/core/ozone/BUILD.gn b/src/core/ozone/BUILD.gn new file mode 100644 index 000000000..b96d8a47a --- /dev/null +++ b/src/core/ozone/BUILD.gn @@ -0,0 +1,25 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +source_set("qt") { + sources = [ + "ozone_platform_qt.h", + "ozone_platform_qt.cpp", + ] + + import("//ui/base/ui_features.gni") + import("//ui/gl/features.gni") + + deps = [ + "//base", + "//ui/ozone:ozone_base", + "//ui/ozone/common", + ] + + defines = [ "OZONE_IMPLEMENTATION" ] + + if (is_linux && !is_desktop_linux) { + deps += [ "//ui/events/ozone:events_ozone_evdev"] + } +} diff --git a/src/core/ozone/gl_context_qt.cpp b/src/core/ozone/gl_context_qt.cpp index ec49414b0..c4a075544 100644 --- a/src/core/ozone/gl_context_qt.cpp +++ b/src/core/ozone/gl_context_qt.cpp @@ -119,14 +119,21 @@ void* GLContextHelper::getGlXConfig() void* GLContextHelper::getEGLDisplay() { +#ifdef Q_OS_WIN + // Windows QPA plugin does not implement resourceForIntegration for "egldisplay". + // Use resourceForContext instead. + return resourceForContext(QByteArrayLiteral("egldisplay")); +#else return resourceForIntegration(QByteArrayLiteral("egldisplay")); +#endif } void* GLContextHelper::getXDisplay() { - if (QGuiApplication::platformName() != QLatin1String("xcb")) - return nullptr; - return qApp->platformNativeInterface()->nativeResourceForScreen(QByteArrayLiteral("display"), qApp->primaryScreen()); + QPlatformNativeInterface *pni = QGuiApplication::platformNativeInterface(); + if (pni) + return pni->nativeResourceForScreen(QByteArrayLiteral("display"), qApp->primaryScreen()); + return nullptr; } void* GLContextHelper::getNativeDisplay() diff --git a/src/core/ozone/gl_surface_egl_qt.cpp b/src/core/ozone/gl_surface_egl_qt.cpp index 9fe5985ce..8715a5095 100644 --- a/src/core/ozone/gl_surface_egl_qt.cpp +++ b/src/core/ozone/gl_surface_egl_qt.cpp @@ -44,9 +44,9 @@ #include "gl_context_qt.h" #include "ozone/gl_surface_egl_qt.h" -#include "ui/gl/gl_surface_egl.h" #if !defined(OS_MACOSX) #include "ui/gl/egl_util.h" +#include "ui/gl/gl_surface_egl.h" #include "ui/gl/init/gl_factory.h" // From ANGLE's egl/eglext.h. @@ -302,10 +302,6 @@ void* GLSurfacelessQtEGL::GetShareHandle() return NULL; } -} // namespace gl -#endif // !defined(OS_MACOSX) - -namespace gl { std::string DriverEGL::GetPlatformExtensions() { EGLDisplay display = GLContextHelper::getEGLDisplay(); @@ -317,3 +313,15 @@ std::string DriverEGL::GetPlatformExtensions() return str ? std::string(str) : ""; } } // namespace gl +#else +namespace gl { +struct GL_EXPORT DriverEGL { + static std::string GetPlatformExtensions(); +}; + +std::string DriverEGL::GetPlatformExtensions() +{ + return ""; +} +} // namespace gl +#endif // !defined(OS_MACOSX) diff --git a/src/core/ozone/gl_surface_qt.cpp b/src/core/ozone/gl_surface_qt.cpp index 7cde289ae..551ba888c 100644 --- a/src/core/ozone/gl_surface_qt.cpp +++ b/src/core/ozone/gl_surface_qt.cpp @@ -64,7 +64,6 @@ #include "ozone/gl_surface_wgl_qt.h" #include "gpu/ipc/service/direct_composition_surface_win.h" -#include "ui/gl/gl_context_wgl.h" #include "ui/gl/vsync_provider_win.h" #endif @@ -141,9 +140,6 @@ bool InitializeGLOneOffPlatform() { VSyncProviderWin::InitializeOneOff(); - if (GetGLImplementation() == kGLImplementationOSMesaGL) - return false; - if (GetGLImplementation() == kGLImplementationEGLGLES2) return GLSurfaceEGLQt::InitializeOneOff(); diff --git a/src/core/ozone/gl_surface_wgl_qt.cpp b/src/core/ozone/gl_surface_wgl_qt.cpp index 7c9e87b86..ac27a9c20 100644 --- a/src/core/ozone/gl_surface_wgl_qt.cpp +++ b/src/core/ozone/gl_surface_wgl_qt.cpp @@ -37,9 +37,9 @@ ** ****************************************************************************/ -#if defined(OS_WIN) - #include "gl_surface_wgl_qt.h" + +#if defined(OS_WIN) #include "ui/gl/gl_surface_wgl.h" namespace gl { diff --git a/src/core/ozone/ozone_extra.gni b/src/core/ozone/ozone_extra.gni new file mode 100644 index 000000000..a832f741a --- /dev/null +++ b/src/core/ozone/ozone_extra.gni @@ -0,0 +1,19 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# This list contains the name of external platforms that are passed to the +# --ozone-platform command line argument or used for the ozone_platform build +# config. For example ozone_external_platforms = [ "foo1", "foo2", ... ] +ozone_external_platforms = [ "qt" ] + +# This list contains dependencies for external platforms. Typically, the Ozone +# implementations are placed into ui/ozone/platform/ and so this will look +# something like: +# ozone_external_platform_deps = [ "platform/foo1", "platform/foo_2", ... ] +ozone_external_platform_deps = [] + +# If a platform has unit tests, the corresponding source_set can be listed here +# so that they get included into ozone_unittests. +# ozone_external_platform_test_deps = [ "platform/foo1:foo1_unitests", ... ] +ozone_external_platform_test_deps = [] diff --git a/src/core/ozone/ozone_platform_qt.cpp b/src/core/ozone/ozone_platform_qt.cpp index 905e8f403..eb7610c0f 100644 --- a/src/core/ozone/ozone_platform_qt.cpp +++ b/src/core/ozone/ozone_platform_qt.cpp @@ -37,12 +37,11 @@ ** ****************************************************************************/ -#include "ozone/ozone_platform_qt.h" +#include "ozone_platform_qt.h" #if defined(USE_OZONE) -#include "ozone/surface_factory_qt.h" -#include "ozone/platform_window_qt.h" #include "ui/display/types/native_display_delegate.h" +#include "ui/events/system_input_injector.h" #include "ui/ozone/common/stub_client_native_pixmap_factory.h" #include "ui/ozone/common/stub_overlay_manager.h" #include "ui/ozone/public/cursor_factory_ozone.h" @@ -53,6 +52,9 @@ #include "ui/platform_window/platform_window_init_properties.h" #include "ui/platform_window/platform_window.h" +#include "surface_factory_qt.h" +#include "platform_window_qt.h" + namespace ui { namespace { diff --git a/src/core/ozone/platform_window_qt.h b/src/core/ozone/platform_window_qt.h index b712b706a..bb2fc714b 100644 --- a/src/core/ozone/platform_window_qt.h +++ b/src/core/ozone/platform_window_qt.h @@ -75,6 +75,9 @@ public: void MoveCursorTo(const gfx::Point&) override { } void ConfineCursorToBounds(const gfx::Rect&) override { } PlatformImeController* GetPlatformImeController() override { return nullptr; } + void SetRestoredBoundsInPixels(const gfx::Rect& bounds) override { } + gfx::Rect GetRestoredBoundsInPixels() const override { return gfx::Rect(); } + // PlatformEventDispatcher: bool CanDispatchEvent(const PlatformEvent& event) override; uint32_t DispatchEvent(const PlatformEvent& event) override; diff --git a/src/core/ozone/surface_factory_qt.cpp b/src/core/ozone/surface_factory_qt.cpp index f69520b70..5420b4809 100644 --- a/src/core/ozone/surface_factory_qt.cpp +++ b/src/core/ozone/surface_factory_qt.cpp @@ -38,10 +38,9 @@ ****************************************************************************/ #include "surface_factory_qt.h" -#include "qtwebenginecoreglobal_p.h" #include "gl_context_qt.h" #include "gl_ozone_egl_qt.h" -#if QT_CONFIG(webengine_ozone_x11) +#if defined(USE_GLX) #include "gl_ozone_glx_qt.h" #endif @@ -58,7 +57,7 @@ namespace QtWebEngineCore { SurfaceFactoryQt::SurfaceFactoryQt() { Q_ASSERT(qApp); -#if QT_CONFIG(webengine_ozone_x11) +#if defined(USE_GLX) if (GLContextHelper::getGlXConfig()) { m_impl = gl::kGLImplementationDesktopGL; m_ozone.reset(new ui::GLOzoneGLXQt()); diff --git a/src/core/permission_manager_qt.cpp b/src/core/permission_manager_qt.cpp index b999f4186..be4d6e598 100644 --- a/src/core/permission_manager_qt.cpp +++ b/src/core/permission_manager_qt.cpp @@ -61,8 +61,13 @@ ProfileAdapter::PermissionType toQt(content::PermissionType type) return ProfileAdapter::AudioCapturePermission; case content::PermissionType::VIDEO_CAPTURE: return ProfileAdapter::VideoCapturePermission; - case content::PermissionType::FLASH: + case content::PermissionType::CLIPBOARD_READ: + return ProfileAdapter::ClipboardRead; + case content::PermissionType::CLIPBOARD_WRITE: + return ProfileAdapter::ClipboardWrite; case content::PermissionType::NOTIFICATIONS: + return ProfileAdapter::NotificationPermission; + case content::PermissionType::FLASH: case content::PermissionType::MIDI_SYSEX: case content::PermissionType::PROTECTED_MEDIA_IDENTIFIER: case content::PermissionType::MIDI: @@ -70,13 +75,11 @@ ProfileAdapter::PermissionType toQt(content::PermissionType type) case content::PermissionType::BACKGROUND_SYNC: case content::PermissionType::SENSORS: case content::PermissionType::ACCESSIBILITY_EVENTS: - break; - case content::PermissionType::CLIPBOARD_READ: - return ProfileAdapter::ClipboardRead; - case content::PermissionType::CLIPBOARD_WRITE: - return ProfileAdapter::ClipboardWrite; case content::PermissionType::PAYMENT_HANDLER: + case content::PermissionType::BACKGROUND_FETCH: + case content::PermissionType::IDLE_DETECTION: case content::PermissionType::NUM: + NOTIMPLEMENTED() << "Unsupported permission type: " << static_cast<int>(type); break; } return ProfileAdapter::UnsupportedPermission; @@ -187,6 +190,9 @@ int PermissionManagerQt::RequestPermission(content::PermissionType permission, m_requests.insert(request_id, request); if (permissionType == ProfileAdapter::GeolocationPermission) contentsDelegate->requestGeolocationPermission(request.origin); + else if (permissionType == ProfileAdapter::NotificationPermission) + contentsDelegate->requestUserNotificationPermission(request.origin); + return request_id; } @@ -235,6 +241,8 @@ int PermissionManagerQt::RequestPermissions(const std::vector<content::Permissio const ProfileAdapter::PermissionType permissionType = toQt(permission); if (permissionType == ProfileAdapter::GeolocationPermission) contentsDelegate->requestGeolocationPermission(request.origin); + else if (permissionType == ProfileAdapter::NotificationPermission) + contentsDelegate->requestUserNotificationPermission(request.origin); } return request_id; } @@ -294,8 +302,8 @@ void PermissionManagerQt::ResetPermission( int PermissionManagerQt::SubscribePermissionStatusChange( content::PermissionType permission, + content::RenderFrameHost * /* render_frame_host */, const GURL& requesting_origin, - const GURL& /*embedding_origin*/, const base::Callback<void(blink::mojom::PermissionStatus)>& callback) { int subscriber_id = ++m_subscriberIdCount; @@ -311,7 +319,7 @@ int PermissionManagerQt::SubscribePermissionStatusChange( void PermissionManagerQt::UnsubscribePermissionStatusChange(int subscription_id) { if (!m_subscribers.remove(subscription_id)) - qWarning() << "PermissionManagerQt::UnsubscribePermissionStatusChange called on unknown subscription id" << subscription_id; + LOG(WARNING) << "PermissionManagerQt::UnsubscribePermissionStatusChange called on unknown subscription id" << subscription_id; } } // namespace QtWebEngineCore diff --git a/src/core/permission_manager_qt.h b/src/core/permission_manager_qt.h index b3bd3dc7a..89eb6cf85 100644 --- a/src/core/permission_manager_qt.h +++ b/src/core/permission_manager_qt.h @@ -92,8 +92,8 @@ public: int SubscribePermissionStatusChange( content::PermissionType permission, + content::RenderFrameHost* render_frame_host, const GURL& requesting_origin, - const GURL& embedding_origin, const base::Callback<void(blink::mojom::PermissionStatus)>& callback) override; void UnsubscribePermissionStatusChange(int subscription_id) override; diff --git a/src/core/platform_notification_service_qt.cpp b/src/core/platform_notification_service_qt.cpp new file mode 100644 index 000000000..f3457c7aa --- /dev/null +++ b/src/core/platform_notification_service_qt.cpp @@ -0,0 +1,208 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "platform_notification_service_qt.h" + +#include "chrome/common/pref_names.h" +#include "components/prefs/pref_service.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/permission_type.h" +#include "content/public/browser/notification_event_dispatcher.h" +#include "ui/message_center/public/cpp/notification_delegate.h" + +#include "profile_adapter.h" +#include "profile_adapter_client.h" +#include "profile_qt.h" +#include "user_notification_controller.h" +#include "resource_context_qt.h" +#include "type_conversion.h" + +#include <QSharedPointer> + +namespace QtWebEngineCore { + +struct NonPersistentNotificationDelegate : UserNotificationController::Delegate { + NonPersistentNotificationDelegate(const std::string &id) : notification_id(id) { } + + virtual void shown() override { + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + if (auto inst = content::NotificationEventDispatcher::GetInstance()) + inst->DispatchNonPersistentShowEvent(notification_id); + } + + virtual void clicked() override { + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + if (auto inst = content::NotificationEventDispatcher::GetInstance()) + inst->DispatchNonPersistentClickEvent(notification_id, base::DoNothing()); + } + + virtual void closed(bool /*by_user*/) override { + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + if (auto inst = content::NotificationEventDispatcher::GetInstance()) + inst->DispatchNonPersistentCloseEvent(notification_id, base::DoNothing()); + } + + const std::string notification_id; +}; + +struct PersistentNotificationDelegate : UserNotificationController::Delegate { + PersistentNotificationDelegate(content::BrowserContext *context, const std::string &id, const GURL &origin) + : browser_context(context), notification_id(id), origin(origin) { } + + virtual void shown() override { } + + virtual void clicked() override { + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + if (auto inst = content::NotificationEventDispatcher::GetInstance()) + inst->DispatchNotificationClickEvent(browser_context, notification_id, origin, base::nullopt, base::nullopt, base::DoNothing()); + } + + virtual void closed(bool by_user) override { + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + if (auto inst = content::NotificationEventDispatcher::GetInstance()) + inst->DispatchNotificationCloseEvent(browser_context, notification_id, origin, by_user, base::DoNothing()); + } + + content::BrowserContext *browser_context; + const std::string notification_id; + const GURL origin; +}; + + +PlatformNotificationServiceQt::PlatformNotificationServiceQt() {} + +PlatformNotificationServiceQt::~PlatformNotificationServiceQt() {} + +void PlatformNotificationServiceQt::DisplayNotification( + content::BrowserContext *browser_context, + const std::string ¬ification_id, + const GURL &origin, + const blink::PlatformNotificationData ¬ificationData, + const blink::NotificationResources ¬ificationResources) +{ + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + ProfileQt *profile = static_cast<ProfileQt*>(browser_context); + + auto delegate = new NonPersistentNotificationDelegate(notification_id); + QSharedPointer<UserNotificationController> controller( + new UserNotificationController(notificationData, notificationResources, origin, delegate)); + + profile->profileAdapter()->ephemeralNotifications().insert(QByteArray::fromStdString(notification_id), controller); + + const QList<ProfileAdapterClient *> clients = profile->profileAdapter()->clients(); + for (ProfileAdapterClient *client : clients) + client->showNotification(controller); +} + +void PlatformNotificationServiceQt::DisplayPersistentNotification( + content::BrowserContext *browser_context, + const std::string ¬ification_id, + const GURL &service_worker_origin, + const GURL &origin, + const blink::PlatformNotificationData ¬ificationData, + const blink::NotificationResources ¬ificationResources) +{ + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + ProfileQt * profile = static_cast<ProfileQt*>(browser_context); + + auto delegate = new PersistentNotificationDelegate(profile, notification_id, service_worker_origin); + QSharedPointer<UserNotificationController> controller( + new UserNotificationController(notificationData, notificationResources, service_worker_origin, delegate)); + + profile->profileAdapter()->persistentNotifications().insert(QByteArray::fromStdString(notification_id), controller); + const QList<ProfileAdapterClient *> clients = profile->profileAdapter()->clients(); + for (ProfileAdapterClient *client : clients) + client->showNotification(controller); +} + +void PlatformNotificationServiceQt::CloseNotification( + content::BrowserContext *browser_context, + const std::string ¬ification_id) +{ + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + ProfileQt *profile = static_cast<ProfileQt*>(browser_context); + + QSharedPointer<UserNotificationController> notificationController = + profile->profileAdapter()->ephemeralNotifications().take(QByteArray::fromStdString(notification_id)).lock(); + if (notificationController) + notificationController->closeNotification(); +} + +void PlatformNotificationServiceQt::ClosePersistentNotification( + content::BrowserContext *browser_context, + const std::string ¬ification_id) +{ + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + ProfileQt *profile = static_cast<ProfileQt*>(browser_context); + + QSharedPointer<UserNotificationController> notificationController = + profile->profileAdapter()->persistentNotifications().take(QByteArray::fromStdString(notification_id)); + if (notificationController) + notificationController->closeNotification(); +} + +void PlatformNotificationServiceQt::GetDisplayedNotifications( + content::BrowserContext *browser_context, + const DisplayedNotificationsCallback &callback) +{ + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + ProfileQt *profile = static_cast<ProfileQt *>(browser_context); + + std::unique_ptr<std::set<std::string>> movableStdStringSet = std::make_unique<std::set<std::string>>(); + auto it = profile->profileAdapter()->persistentNotifications().constBegin(); + const auto end = profile->profileAdapter()->persistentNotifications().constEnd(); + while (it != end) { + if (it.value()->isShown()) + movableStdStringSet->insert(it.key().toStdString()); + ++it; + } + + callback.Run(std::move(movableStdStringSet), true /* supports_synchronization */); +} + +int64_t PlatformNotificationServiceQt::ReadNextPersistentNotificationId(content::BrowserContext *browser_context) +{ + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + auto prefs = static_cast<ProfileQt *>(browser_context)->GetPrefs(); + int64_t nextId = prefs->GetInteger(prefs::kNotificationNextPersistentId) + 1; + prefs->SetInteger(prefs::kNotificationNextPersistentId, nextId); + return nextId; +} + +} // namespace QtWebEngineCore diff --git a/src/core/platform_notification_service_qt.h b/src/core/platform_notification_service_qt.h new file mode 100644 index 000000000..66cee9ed0 --- /dev/null +++ b/src/core/platform_notification_service_qt.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef PLATFORM_NOTIFICATION_SERVICE_QT_H +#define PLATFORM_NOTIFICATION_SERVICE_QT_H + +#include "content/public/browser/platform_notification_service.h" + +namespace QtWebEngineCore { + +class PlatformNotificationServiceQt : public content::PlatformNotificationService { +public: + PlatformNotificationServiceQt(); + ~PlatformNotificationServiceQt() override; + + // Displays the notification described in |notification_data| to the user. A + // closure through which the notification can be closed will be stored in the + // |cancel_callback| argument. This method must be called on the UI thread. + void DisplayNotification(content::BrowserContext* browser_context, + const std::string& notification_id, + const GURL& origin, + const blink::PlatformNotificationData& notificationData, + const blink::NotificationResources& notificationResources) override; + + // Displays the persistent notification described in |notification_data| to + // the user. This method must be called on the UI thread. + void DisplayPersistentNotification(content::BrowserContext* browser_context, + const std::string& notification_id, + const GURL& service_worker_origin, + const GURL& origin, + const blink::PlatformNotificationData& notification_data, + const blink::NotificationResources& notification_resources) override; + + // Closes the notification identified by |notification_id|. + // This method must be called on the UI thread. + void CloseNotification(content::BrowserContext* browser_context, const std::string& notification_id) override; + + // Closes the persistent notification identified by |persistent_notification_id|. + // This method must be called on the UI thread. + void ClosePersistentNotification(content::BrowserContext* browser_context, const std::string& notification_id) override; + + // Retrieves the ids of all currently displaying notifications and + // posts |callback| with the result. + void GetDisplayedNotifications(content::BrowserContext* browser_context, const DisplayedNotificationsCallback& callback) override; + + // Reads the value of the next persistent notification ID from the profile and + // increments the value, as it is called once per notification write. + virtual int64_t ReadNextPersistentNotificationId(content::BrowserContext* browser_context) override; + + // Records a given notification to UKM. + virtual void RecordNotificationUkmEvent(content::BrowserContext*, const content::NotificationDatabaseData&) override { } +}; + +} // namespace QtWebEngineCore + +#endif // PLATFORM_NOTIFICATION_SERVICE_QT_H diff --git a/src/core/printing/pdfium_document_wrapper_qt.cpp b/src/core/printing/pdfium_document_wrapper_qt.cpp index a18258d0e..6f415b50b 100644 --- a/src/core/printing/pdfium_document_wrapper_qt.cpp +++ b/src/core/printing/pdfium_document_wrapper_qt.cpp @@ -48,14 +48,13 @@ namespace QtWebEngineCore { int PdfiumDocumentWrapperQt::m_libraryUsers = 0; -class QWEBENGINECORE_PRIVATE_EXPORT PdfiumPageWrapperQt { +class PdfiumPageWrapperQt { public: - PdfiumPageWrapperQt(FPDF_DOCUMENT data, int pageIndex, int targetWidth, int targetHeight) + PdfiumPageWrapperQt(FPDF_DOCUMENT data, int pageIndex) : m_pageData(FPDF_LoadPage(data, pageIndex)) , m_width(FPDF_GetPageWidth(m_pageData)) , m_height(FPDF_GetPageHeight(m_pageData)) - , m_index(pageIndex) - , m_image(createImage(targetWidth, targetHeight)) + , m_image(createImage()) { } @@ -63,7 +62,6 @@ public: : m_pageData(nullptr) , m_width(-1) , m_height(-1) - , m_index(-1) , m_image(QImage()) { } @@ -79,16 +77,11 @@ public: } private: - QImage createImage(int targetWidth, int targetHeight) + QImage createImage() { Q_ASSERT(m_pageData); - if (targetWidth <= 0) - targetWidth = m_width; - if (targetHeight <= 0) - targetHeight = m_height; - - QImage image(targetWidth, targetHeight, QImage::Format_ARGB32); + QImage image(m_width * 2, m_height * 2, QImage::Format_ARGB32); Q_ASSERT(!image.isNull()); image.fill(0xFFFFFFFF); @@ -102,22 +95,19 @@ private: 0, 0); FPDFBitmap_Destroy(bitmap); bitmap = nullptr; - return std::move(image); + return image; } private: FPDF_PAGE m_pageData; int m_width; int m_height; - int m_index; QImage m_image; }; PdfiumDocumentWrapperQt::PdfiumDocumentWrapperQt(const void *pdfData, size_t size, - const QSize& imageSize, const char *password) - : m_imageSize(imageSize * 2.0) { Q_ASSERT(pdfData); Q_ASSERT(size); @@ -140,11 +130,17 @@ QImage PdfiumDocumentWrapperQt::pageAsQImage(size_t index) return QImage(); } - PdfiumPageWrapperQt pageWrapper((FPDF_DOCUMENT)m_documentHandle, index, - m_imageSize.width(), m_imageSize.height()); + PdfiumPageWrapperQt pageWrapper((FPDF_DOCUMENT)m_documentHandle, index); return pageWrapper.image(); } +bool PdfiumDocumentWrapperQt::pageIsLandscape(size_t index) +{ + double width = 0, height = 0; + FPDF_GetPageSizeByIndex((FPDF_DOCUMENT)m_documentHandle, index, &width, &height); + return (width > height); +} + PdfiumDocumentWrapperQt::~PdfiumDocumentWrapperQt() { FPDF_CloseDocument((FPDF_DOCUMENT)m_documentHandle); diff --git a/src/core/printing/pdfium_document_wrapper_qt.h b/src/core/printing/pdfium_document_wrapper_qt.h index f4ac557a0..121742aa3 100644 --- a/src/core/printing/pdfium_document_wrapper_qt.h +++ b/src/core/printing/pdfium_document_wrapper_qt.h @@ -58,20 +58,19 @@ namespace QtWebEngineCore { class PdfiumPageWrapperQt; -class QWEBENGINECORE_PRIVATE_EXPORT PdfiumDocumentWrapperQt +class Q_WEBENGINECORE_PRIVATE_EXPORT PdfiumDocumentWrapperQt { public: - PdfiumDocumentWrapperQt(const void *pdfData, size_t size, const QSize &imageSize, - const char *password = nullptr); + PdfiumDocumentWrapperQt(const void *pdfData, size_t size, const char *password = nullptr); virtual ~PdfiumDocumentWrapperQt(); QImage pageAsQImage(size_t index); + bool pageIsLandscape(size_t index); int pageCount() const { return m_pageCount; } private: static int m_libraryUsers; int m_pageCount; void *m_documentHandle; - QSize m_imageSize; }; } // namespace QtWebEngineCore diff --git a/src/core/printing/print_view_manager_base_qt.cpp b/src/core/printing/print_view_manager_base_qt.cpp index 0e7239ef8..52f4481bb 100644 --- a/src/core/printing/print_view_manager_base_qt.cpp +++ b/src/core/printing/print_view_manager_base_qt.cpp @@ -52,6 +52,7 @@ #include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "base/single_thread_task_runner.h" +#include "base/task/post_task.h" #include "base/timer/timer.h" #include "base/values.h" #include "chrome/browser/chrome_notification_types.h" @@ -59,12 +60,13 @@ #include "chrome/browser/printing/print_job_manager.h" #include "chrome/browser/printing/printer_query.h" #include "components/printing/common/print_messages.h" +#include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/notification_service.h" #include "content/public/browser/notification_types.h" -#include "printing/pdf_metafile_skia.h" +#include "printing/metafile_skia.h" #include "printing/print_job_constants.h" #include "printing/printed_document.h" @@ -123,8 +125,8 @@ void PrintViewManagerBaseQt::PrintDocument(printing::PrintedDocument *document, const gfx::Rect &content_area, const gfx::Point &offsets) { - std::unique_ptr<printing::PdfMetafileSkia> metafile = - std::make_unique<printing::PdfMetafileSkia>(); + std::unique_ptr<printing::MetafileSkia> metafile = + std::make_unique<printing::MetafileSkia>(); CHECK(metafile->InitFromData(print_data->front(), print_data->size())); // Update the rendered document. It will send notifications to the listener. @@ -155,21 +157,19 @@ void PrintViewManagerBaseQt::OnDidPrintDocument(content::RenderFrameHost* /*rend return; const PrintHostMsg_DidPrintContent_Params &content = params.content; - if (!base::SharedMemory::IsHandleValid(content.metafile_data_handle)) { + if (!content.metafile_data_region.IsValid()) { NOTREACHED() << "invalid memory handle"; web_contents()->Stop(); return; } - std::unique_ptr<base::SharedMemory> shared_buf = - std::make_unique<base::SharedMemory>(content.metafile_data_handle, true); - if (!shared_buf->Map(content.data_size)) { + auto data = base::RefCountedSharedMemoryMapping::CreateFromWholeRegion(content.metafile_data_region); + if (!data) { NOTREACHED() << "couldn't map"; web_contents()->Stop(); return; } - auto data = base::MakeRefCounted<base::RefCountedSharedMemory>( - std::move(shared_buf), content.data_size); + PrintDocument(document, data, params.page_size, params.content_area, params.physical_offsets); } @@ -455,7 +455,7 @@ bool PrintViewManagerBaseQt::RunInnerMessageLoop() { // Need to enable recursive task. { - base::MessageLoop::ScopedNestableTaskAllower allow; + base::MessageLoopCurrent::ScopedNestableTaskAllower allow; run_loop.Run(); } @@ -516,9 +516,8 @@ void PrintViewManagerBaseQt::ReleasePrinterQuery() printerQuery = m_printerQueriesQueue->PopPrinterQuery(cookie); if (!printerQuery.get()) return; - content::BrowserThread::PostTask( - content::BrowserThread::IO, FROM_HERE, - base::BindOnce(&printing::PrinterQuery::StopWorker, printerQuery.get())); + base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::IO}, + base::BindOnce(&printing::PrinterQuery::StopWorker, printerQuery.get())); } // Originally from print_preview_message_handler.cc: @@ -528,7 +527,7 @@ void PrintViewManagerBaseQt::StopWorker(int documentCookie) { scoped_refptr<printing::PrinterQuery> printer_query = m_printerQueriesQueue->PopPrinterQuery(documentCookie); if (printer_query.get()) { - content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, + base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::IO}, base::BindOnce(&printing::PrinterQuery::StopWorker, printer_query)); } } diff --git a/src/core/printing/print_view_manager_qt.cpp b/src/core/printing/print_view_manager_qt.cpp index 65c059d88..b6a2b42ec 100644 --- a/src/core/printing/print_view_manager_qt.cpp +++ b/src/core/printing/print_view_manager_qt.cpp @@ -53,50 +53,43 @@ #include "base/values.h" #include "base/memory/ref_counted_memory.h" -#include "base/task_scheduler/post_task.h" +#include "base/task/post_task.h" #include "chrome/browser/printing/print_job_manager.h" #include "chrome/browser/printing/printer_query.h" #include "components/printing/common/print_messages.h" #include "content/browser/renderer_host/render_view_host_impl.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 "content/public/browser/render_frame_host.h" #include "content/public/common/web_preferences.h" -#include "printing/pdf_metafile_skia.h" +#include "printing/metafile_skia.h" #include "printing/print_job_constants.h" #include "printing/units.h" -DEFINE_WEB_CONTENTS_USER_DATA_KEY(QtWebEngineCore::PrintViewManagerQt); - namespace { static const qreal kMicronsToMillimeter = 1000.0f; -static std::vector<char> -GetStdVectorFromHandle(base::SharedMemoryHandle handle, uint32_t data_size) +static QSharedPointer<QByteArray> GetStdVectorFromHandle(const base::ReadOnlySharedMemoryRegion &handle) { - std::unique_ptr<base::SharedMemory> shared_buf( - new base::SharedMemory(handle, true)); - - if (!shared_buf->Map(data_size)) { - return std::vector<char>(); - } + base::ReadOnlySharedMemoryMapping map = handle.Map(); + if (!map.IsValid()) + return QSharedPointer<QByteArray>(new QByteArray); - char* data = static_cast<char*>(shared_buf->memory()); - return std::vector<char>(data, data + data_size); + const char* data = static_cast<const char*>(map.memory()); + return QSharedPointer<QByteArray>(new QByteArray(data, map.size())); } static scoped_refptr<base::RefCountedBytes> -GetBytesFromHandle(base::SharedMemoryHandle handle, uint32_t data_size) +GetBytesFromHandle(const base::ReadOnlySharedMemoryRegion &handle) { - std::unique_ptr<base::SharedMemory> shared_buf(new base::SharedMemory(handle, true)); - - if (!shared_buf->Map(data_size)) { + base::ReadOnlySharedMemoryMapping map = handle.Map(); + if (!map.IsValid()) return nullptr; - } - unsigned char* data = static_cast<unsigned char*>(shared_buf->memory()); - std::vector<unsigned char> dataVector(data, data + data_size); + const unsigned char* data = static_cast<const unsigned char*>(map.memory()); + std::vector<unsigned char> dataVector(data, data + map.size()); return base::RefCountedBytes::TakeVector(&dataVector); } @@ -105,18 +98,17 @@ static void SavePdfFile(scoped_refptr<base::RefCountedBytes> data, const base::FilePath &path, const QtWebEngineCore::PrintViewManagerQt::PrintToPDFFileCallback &saveCallback) { - base::AssertBlockingAllowed(); + base::AssertBlockingAllowedDeprecated(); DCHECK_GT(data->size(), 0U); - printing::PdfMetafileSkia metafile; + printing::MetafileSkia metafile; metafile.InitFromData(static_cast<const void*>(data->front()), data->size()); base::File file(path, base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE); bool success = file.IsValid() && metafile.SaveTo(&file); - content::BrowserThread::PostTask(content::BrowserThread::UI, - FROM_HERE, - base::Bind(saveCallback, success)); + base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(saveCallback, success)); } static base::DictionaryValue *createPrintSettings() @@ -139,14 +131,15 @@ static base::DictionaryValue *createPrintSettings() printSettings->SetInteger(printing::kSettingDuplexMode, printing::SIMPLEX); printSettings->SetInteger(printing::kSettingCopies, 1); + printSettings->SetInteger(printing::kSettingPagesPerSheet, 1); printSettings->SetBoolean(printing::kSettingCollate, false); // printSettings->SetBoolean(printing::kSettingGenerateDraftData, false); printSettings->SetBoolean(printing::kSettingPreviewModifiable, false); - printSettings->SetBoolean(printing::kSettingShouldPrintSelectionOnly, false); - printSettings->SetBoolean(printing::kSettingShouldPrintBackgrounds, true); - printSettings->SetBoolean(printing::kSettingHeaderFooterEnabled, false); - printSettings->SetBoolean(printing::kSettingRasterizePdf, false); + printSettings->SetKey(printing::kSettingShouldPrintSelectionOnly, base::Value(false)); + printSettings->SetKey(printing::kSettingShouldPrintBackgrounds, base::Value(true)); + printSettings->SetKey(printing::kSettingHeaderFooterEnabled, base::Value(false)); + printSettings->SetKey(printing::kSettingRasterizePdf, base::Value(false)); printSettings->SetInteger(printing::kSettingScaleFactor, 100); printSettings->SetString(printing::kSettingDeviceName, ""); printSettings->SetInteger(printing::kPreviewUIID, 12345678); @@ -224,16 +217,16 @@ void PrintViewManagerQt::PrintToPDFFileWithCallback(const QPageLayout &pageLayou return; if (m_printSettings || !filePath.length()) { - content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, - base::Bind(callback, false)); + base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(callback, false)); return; } m_pdfOutputPath = toFilePath(filePath); m_pdfSaveCallback = callback; if (!PrintToPDFInternal(pageLayout, printInColor)) { - content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, - base::Bind(callback, false)); + base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(callback, false)); resetPdfState(); } } @@ -248,16 +241,15 @@ void PrintViewManagerQt::PrintToPDFWithCallback(const QPageLayout &pageLayout, // If there already is a pending print in progress, don't try starting another one. if (m_printSettings) { - content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, - base::Bind(callback, std::vector<char>())); + base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(callback, QSharedPointer<QByteArray>())); return; } m_pdfPrintCallback = callback; if (!PrintToPDFInternal(pageLayout, printInColor, useCustomMargins)) { - content::BrowserThread::PostTask(content::BrowserThread::UI, - FROM_HERE, - base::Bind(callback, std::vector<char>())); + base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(callback, QSharedPointer<QByteArray>())); resetPdfState(); } @@ -360,21 +352,18 @@ void PrintViewManagerQt::OnMetafileReadyForPrinting(content::RenderFrameHost* rf StopWorker(params.document_cookie); // Create local copies so we can reset the state and take a new pdf print job. - base::Callback<void(const std::vector<char>&)> pdf_print_callback = m_pdfPrintCallback; - base::Callback<void(bool)> pdf_save_callback = m_pdfSaveCallback; + PrintToPDFCallback pdf_print_callback = std::move(m_pdfPrintCallback); + PrintToPDFFileCallback pdf_save_callback = std::move(m_pdfSaveCallback); base::FilePath pdfOutputPath = m_pdfOutputPath; resetPdfState(); if (!pdf_print_callback.is_null()) { - std::vector<char> data_vector = GetStdVectorFromHandle(params.content.metafile_data_handle, - params.content.data_size); - content::BrowserThread::PostTask(content::BrowserThread::UI, - FROM_HERE, - base::Bind(pdf_print_callback, data_vector)); + QSharedPointer<QByteArray> data_array = GetStdVectorFromHandle(params.content.metafile_data_region); + base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(pdf_print_callback, data_array)); } else { - scoped_refptr<base::RefCountedBytes> data_bytes - = GetBytesFromHandle(params.content.metafile_data_handle, params.content.data_size); + scoped_refptr<base::RefCountedBytes> data_bytes = GetBytesFromHandle(params.content.metafile_data_region); base::PostTaskWithTraits(FROM_HERE, {base::MayBlock()}, base::BindOnce(&SavePdfFile, data_bytes, pdfOutputPath, pdf_save_callback)); } @@ -394,9 +383,8 @@ void PrintViewManagerQt::DidStartLoading() void PrintViewManagerQt::NavigationStopped() { if (!m_pdfPrintCallback.is_null()) { - content::BrowserThread::PostTask(content::BrowserThread::UI, - FROM_HERE, - base::Bind(m_pdfPrintCallback, std::vector<char>())); + base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(m_pdfPrintCallback, QSharedPointer<QByteArray>())); } resetPdfState(); PrintViewManagerBaseQt::NavigationStopped(); @@ -406,9 +394,8 @@ void PrintViewManagerQt::RenderProcessGone(base::TerminationStatus status) { PrintViewManagerBaseQt::RenderProcessGone(status); if (!m_pdfPrintCallback.is_null()) { - content::BrowserThread::PostTask(content::BrowserThread::UI, - FROM_HERE, - base::Bind(m_pdfPrintCallback, std::vector<char>())); + base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(m_pdfPrintCallback, QSharedPointer<QByteArray>())); } resetPdfState(); } @@ -450,4 +437,6 @@ void PrintViewManagerQt::PrintPreviewDone() { m_printPreviewRfh = nullptr; } +WEB_CONTENTS_USER_DATA_KEY_IMPL(PrintViewManagerQt) + } // namespace QtWebEngineCore diff --git a/src/core/printing/print_view_manager_qt.h b/src/core/printing/print_view_manager_qt.h index 209be8782..20b988200 100644 --- a/src/core/printing/print_view_manager_qt.h +++ b/src/core/printing/print_view_manager_qt.h @@ -56,6 +56,8 @@ #include "content/public/browser/notification_registrar.h" #include "content/public/browser/web_contents_user_data.h" +#include <QSharedPointer> + struct PrintHostMsg_RequestPrintPreview_Params; struct PrintHostMsg_DidPreviewDocument_Params; @@ -83,7 +85,7 @@ class PrintViewManagerQt { public: ~PrintViewManagerQt() override; - typedef base::Callback<void(const std::vector<char> &result)> PrintToPDFCallback; + typedef base::Callback<void(QSharedPointer<QByteArray> result)> PrintToPDFCallback; typedef base::Callback<void(bool success)> PrintToPDFFileCallback; // Method to print a page to a Pdf document with page size \a pageSize in location \a filePath. @@ -135,6 +137,7 @@ private: void PrintPreviewDone(); private: + WEB_CONTENTS_USER_DATA_KEY_DECL() content::RenderFrameHost *m_printPreviewRfh; base::FilePath m_pdfOutputPath; PrintToPDFCallback m_pdfPrintCallback; diff --git a/src/core/printing/printing_message_filter_qt.cpp b/src/core/printing/printing_message_filter_qt.cpp index db59a0807..d1e86343f 100644 --- a/src/core/printing/printing_message_filter_qt.cpp +++ b/src/core/printing/printing_message_filter_qt.cpp @@ -183,11 +183,9 @@ void PrintingMessageFilterQt::OnScriptedPrintReply( } } -void PrintingMessageFilterQt::OnUpdatePrintSettings( - int document_cookie, const base::DictionaryValue& job_settings, - IPC::Message* reply_msg) { - std::unique_ptr<base::DictionaryValue> new_settings(job_settings.DeepCopy()); - +void PrintingMessageFilterQt::OnUpdatePrintSettings(int document_cookie, + base::Value job_settings, + IPC::Message* reply_msg) { scoped_refptr<printing::PrinterQuery> printer_query; printer_query = queue_->PopPrinterQuery(document_cookie); if (!printer_query.get()) { @@ -195,7 +193,7 @@ void PrintingMessageFilterQt::OnUpdatePrintSettings( content::ChildProcessHost::kInvalidUniqueID, MSG_ROUTING_NONE); } printer_query->SetSettings( - std::move(new_settings), + std::move(job_settings), base::Bind(&PrintingMessageFilterQt::OnUpdatePrintSettingsReply, this, printer_query, reply_msg)); } diff --git a/src/core/printing/printing_message_filter_qt.h b/src/core/printing/printing_message_filter_qt.h index 72e4b43b4..f1a3514c5 100644 --- a/src/core/printing/printing_message_filter_qt.h +++ b/src/core/printing/printing_message_filter_qt.h @@ -110,7 +110,7 @@ class PrintingMessageFilterQt : public content::BrowserMessageFilter { // handled by the print worker thread and the UI thread. The reply occurs on // the IO thread. void OnUpdatePrintSettings(int document_cookie, - const base::DictionaryValue& job_settings, + base::Value job_settings, IPC::Message* reply_msg); void OnUpdatePrintSettingsReply(scoped_refptr<printing::PrinterQuery> printer_query, IPC::Message* reply_msg); diff --git a/src/core/process_main.cpp b/src/core/process_main.cpp index 677f0b10a..d661d3b90 100644 --- a/src/core/process_main.cpp +++ b/src/core/process_main.cpp @@ -44,7 +44,10 @@ #if defined(OS_WIN) #include "sandbox/win/src/sandbox_types.h" #include "content/public/app/sandbox_helper_win.h" -#endif // OS_WIN +#elif defined(OS_MACOSX) +#include "base/logging.h" +#include "sandbox/mac/seatbelt_exec.h" +#endif namespace QtWebEngine { @@ -64,6 +67,13 @@ int processMain(int argc, const char **argv) params.argc = argc; params.argv = argv; #endif // OS_WIN +#if defined(OS_MACOSX) + sandbox::SeatbeltExecServer::CreateFromArgumentsResult seatbelt = + sandbox::SeatbeltExecServer::CreateFromArguments(argv[0], argc, const_cast<char**>(argv)); + if (seatbelt.sandbox_required) { + CHECK(seatbelt.server->InitializeSandbox()); + } +#endif // defined(OS_MACOSX) return content::ContentMain(params); } diff --git a/src/core/process_main.h b/src/core/process_main.h index d171828d5..00c029d9f 100644 --- a/src/core/process_main.h +++ b/src/core/process_main.h @@ -52,6 +52,6 @@ namespace QtWebEngine { -QWEBENGINECORE_PRIVATE_EXPORT int processMain(int argc, const char **argv); +Q_WEBENGINECORE_PRIVATE_EXPORT int processMain(int argc, const char **argv); } // namespace diff --git a/src/core/profile_adapter.cpp b/src/core/profile_adapter.cpp index b04fa0d46..ebb533206 100644 --- a/src/core/profile_adapter.cpp +++ b/src/core/profile_adapter.cpp @@ -45,10 +45,11 @@ #include "content/public/browser/download_manager.h" #include "api/qwebengineurlscheme.h" -#include "content_client_qt.h" +#include "content_browser_client_qt.h" #include "download_manager_delegate_qt.h" #include "net/url_request_context_getter_qt.h" #include "permission_manager_qt.h" +#include "profile_adapter_client.h" #include "profile_qt.h" #include "renderer_host/user_resource_controller_host.h" #include "type_conversion.h" @@ -58,6 +59,10 @@ #include "components/keyed_service/content/browser_context_dependency_manager.h" +#if BUILDFLAG(ENABLE_EXTENSIONS) +#include "extensions/browser/extension_system.h" +#endif + #include <QCoreApplication> #include <QDir> #include <QString> @@ -79,10 +84,12 @@ namespace QtWebEngineCore { ProfileAdapter::ProfileAdapter(const QString &storageName): m_name(storageName) , m_offTheRecord(storageName.isEmpty()) + , m_downloadPath(QStandardPaths::writableLocation(QStandardPaths::DownloadLocation)) , m_httpCacheType(DiskHttpCache) , m_persistentCookiesPolicy(AllowPersistentCookies) , m_visitedLinksPolicy(TrackVisitedLinksOnDisk) , m_httpCacheMaxSize(0) + , m_pageRequestInterceptors(0) { WebEngineContext::current()->addProfileAdapter(this); // creation of profile requires webengine context @@ -90,6 +97,11 @@ ProfileAdapter::ProfileAdapter(const QString &storageName): content::BrowserContext::Initialize(m_profile.data(), toFilePath(dataPath())); // fixme: this should not be here m_profile->m_profileIOData->initializeOnUIThread(); + m_customUrlSchemeHandlers.insert(QByteArrayLiteral("qrc"), &m_qrcHandler); +#if BUILDFLAG(ENABLE_EXTENSIONS) + if (!storageName.isEmpty()) + extensions::ExtensionSystem::Get(m_profile.data())->InitForRegularProfile(true); +#endif } ProfileAdapter::~ProfileAdapter() @@ -102,6 +114,10 @@ ProfileAdapter::~ProfileAdapter() m_profile->GetDownloadManager(m_profile.data())->Shutdown(); m_downloadManagerDelegate.reset(); } +#if QT_CONFIG(ssl) + delete m_clientCertificateStore; +#endif + Q_ASSERT(m_pageRequestInterceptors == 0); } void ProfileAdapter::setStorageName(const QString &storageName) @@ -178,6 +194,22 @@ void ProfileAdapter::removeClient(ProfileAdapterClient *adapterClient) m_clients.removeOne(adapterClient); } +void ProfileAdapter::addPageRequestInterceptor() +{ + ++m_pageRequestInterceptors; + if (m_profile->m_urlRequestContextGetter.get()) + m_profile->m_profileIOData->updateRequestInterceptor(); +} + +void ProfileAdapter::removePageRequestInterceptor() +{ + Q_ASSERT(m_pageRequestInterceptors > 0); + --m_pageRequestInterceptors; + if (m_profile->m_urlRequestContextGetter.get()) + m_profile->m_profileIOData->updateRequestInterceptor(); +} + + void ProfileAdapter::cancelDownload(quint32 downloadId) { downloadManagerDelegate()->cancelDownload(downloadId); @@ -238,6 +270,11 @@ void ProfileAdapter::setDataPath(const QString &path) } } +void ProfileAdapter::setDownloadPath(const QString &path) +{ + m_downloadPath = path.isEmpty() ? QStandardPaths::writableLocation(QStandardPaths::DownloadLocation) : path; +} + QString ProfileAdapter::cachePath() const { if (m_offTheRecord) @@ -296,7 +333,7 @@ QString ProfileAdapter::httpCachePath() const QString ProfileAdapter::httpUserAgent() const { if (m_httpUserAgent.isNull()) - return QString::fromStdString(ContentClientQt::getUserAgent()); + return QString::fromStdString(ContentBrowserClientQt::getUserAgent()); return m_httpUserAgent; } @@ -406,9 +443,39 @@ void ProfileAdapter::setHttpCacheMaxSize(int maxSize) m_profile->m_profileIOData->updateHttpCache(); } -const QHash<QByteArray, QWebEngineUrlSchemeHandler *> &ProfileAdapter::customUrlSchemeHandlers() const +enum class SchemeType { Protected, Overridable, Custom, Unknown }; +static SchemeType schemeType(const QByteArray &canonicalScheme) { - return m_customUrlSchemeHandlers; + static const QSet<QByteArray> blacklist{ + QByteArrayLiteral("about"), + QByteArrayLiteral("blob"), + QByteArrayLiteral("data"), + QByteArrayLiteral("javascript"), + QByteArrayLiteral("qrc"), + // See also kStandardURLSchemes in url/url_util.cc (through url::IsStandard below) + }; + + static const QSet<QByteArray> whitelist{ + QByteArrayLiteral("gopher"), + }; + + bool standardSyntax = url::IsStandard(canonicalScheme.data(), url::Component(0, canonicalScheme.size())); + bool customScheme = QWebEngineUrlScheme::schemeByName(canonicalScheme) != QWebEngineUrlScheme(); + bool blacklisted = blacklist.contains(canonicalScheme); + bool whitelisted = whitelist.contains(canonicalScheme); + + if (whitelisted) + return SchemeType::Overridable; + if (blacklisted || (standardSyntax && !customScheme)) + return SchemeType::Protected; + if (customScheme) + return SchemeType::Custom; + return SchemeType::Unknown; +} + +QWebEngineUrlSchemeHandler *ProfileAdapter::urlSchemeHandler(const QByteArray &scheme) +{ + return m_customUrlSchemeHandlers.value(scheme.toLower()).data(); } const QList<QByteArray> ProfileAdapter::customUrlSchemes() const @@ -422,12 +489,17 @@ void ProfileAdapter::updateCustomUrlSchemeHandlers() m_profile->m_profileIOData->updateJobFactory(); } -bool ProfileAdapter::removeCustomUrlSchemeHandler(QWebEngineUrlSchemeHandler *handler) +void ProfileAdapter::removeUrlSchemeHandler(QWebEngineUrlSchemeHandler *handler) { + Q_ASSERT(handler); bool removedOneOrMore = false; auto it = m_customUrlSchemeHandlers.begin(); while (it != m_customUrlSchemeHandlers.end()) { if (it.value() == handler) { + if (schemeType(it.key()) == SchemeType::Protected) { + qWarning("Cannot remove the URL scheme handler for an internal scheme: %s", it.key().constData()); + continue; + } it = m_customUrlSchemeHandlers.erase(it); removedOneOrMore = true; continue; @@ -436,60 +508,47 @@ bool ProfileAdapter::removeCustomUrlSchemeHandler(QWebEngineUrlSchemeHandler *ha } if (removedOneOrMore) updateCustomUrlSchemeHandlers(); - return removedOneOrMore; } -QWebEngineUrlSchemeHandler *ProfileAdapter::takeCustomUrlSchemeHandler(const QByteArray &scheme) +void ProfileAdapter::removeUrlScheme(const QByteArray &scheme) { - QWebEngineUrlSchemeHandler *handler = m_customUrlSchemeHandlers.take(scheme.toLower()); - if (handler) + QByteArray canonicalScheme = scheme.toLower(); + if (schemeType(canonicalScheme) == SchemeType::Protected) { + qWarning("Cannot remove the URL scheme handler for an internal scheme: %s", scheme.constData()); + return; + } + if (m_customUrlSchemeHandlers.remove(canonicalScheme)) updateCustomUrlSchemeHandlers(); - return handler; } -bool ProfileAdapter::addCustomUrlSchemeHandler(const QByteArray &scheme, QWebEngineUrlSchemeHandler *handler) +void ProfileAdapter::installUrlSchemeHandler(const QByteArray &scheme, QWebEngineUrlSchemeHandler *handler) { - static const QSet<QByteArray> blacklist{ - QByteArrayLiteral("about"), - QByteArrayLiteral("blob"), - QByteArrayLiteral("data"), - QByteArrayLiteral("javascript"), - QByteArrayLiteral("qrc"), - // See also kStandardURLSchemes in url/url_util.cc (through url::IsStandard below) - }; - - static const QSet<QByteArray> whitelist{ - QByteArrayLiteral("gopher"), - }; - - const QByteArray canonicalScheme = scheme.toLower(); - bool standardSyntax = url::IsStandard(canonicalScheme.data(), url::Component(0, canonicalScheme.size())); - bool customScheme = QWebEngineUrlScheme::schemeByName(canonicalScheme) != QWebEngineUrlScheme(); - bool blacklisted = blacklist.contains(canonicalScheme) || (standardSyntax && !customScheme); - bool whitelisted = whitelist.contains(canonicalScheme); + Q_ASSERT(handler); + QByteArray canonicalScheme = scheme.toLower(); + SchemeType type = schemeType(canonicalScheme); - if (blacklisted && !whitelisted) { + if (type == SchemeType::Protected) { qWarning("Cannot install a URL scheme handler overriding internal scheme: %s", scheme.constData()); - return false; + return; } if (m_customUrlSchemeHandlers.value(canonicalScheme, handler) != handler) { qWarning("URL scheme handler already installed for the scheme: %s", scheme.constData()); - return false; + return; } - if (!whitelisted && !customScheme) + if (type == SchemeType::Unknown) qWarning("Please register the custom scheme '%s' via QWebEngineUrlScheme::registerScheme() " "before installing the custom scheme handler.", scheme.constData()); m_customUrlSchemeHandlers.insert(canonicalScheme, handler); updateCustomUrlSchemeHandlers(); - return true; } -void ProfileAdapter::clearCustomUrlSchemeHandlers() +void ProfileAdapter::removeAllUrlSchemeHandlers() { m_customUrlSchemeHandlers.clear(); + m_customUrlSchemeHandlers.insert(QByteArrayLiteral("qrc"), &m_qrcHandler); updateCustomUrlSchemeHandlers(); } @@ -598,7 +657,46 @@ void ProfileAdapter::removeWebContentsAdapterClient(WebContentsAdapterClient *cl void ProfileAdapter::resetVisitedLinksManager() { - m_visitedLinksManager.reset(new VisitedLinksManagerQt(this)); + m_visitedLinksManager.reset(new VisitedLinksManagerQt(m_profile.data(), persistVisitedLinks())); } +void ProfileAdapter::setUseForGlobalCertificateVerification(bool enable) +{ + if (m_usedForGlobalCertificateVerification == enable) + return; + + static QPointer<ProfileAdapter> profileForglobalCertificateVerification; + + m_usedForGlobalCertificateVerification = enable; + if (enable) { + if (profileForglobalCertificateVerification) { + profileForglobalCertificateVerification->m_usedForGlobalCertificateVerification = false; + for (auto *client : qAsConst(profileForglobalCertificateVerification->m_clients)) + client->useForGlobalCertificateVerificationChanged(); + } + profileForglobalCertificateVerification = this; + } else { + Q_ASSERT(profileForglobalCertificateVerification); + Q_ASSERT(profileForglobalCertificateVerification == this); + profileForglobalCertificateVerification = nullptr; + } + + if (m_profile->m_urlRequestContextGetter.get()) + m_profile->m_profileIOData->updateUsedForGlobalCertificateVerification(); +} + +bool ProfileAdapter::isUsedForGlobalCertificateVerification() const +{ + return m_usedForGlobalCertificateVerification; +} + +#if QT_CONFIG(ssl) +QWebEngineClientCertificateStore *ProfileAdapter::clientCertificateStore() +{ + if (!m_clientCertificateStore) + m_clientCertificateStore = new QWebEngineClientCertificateStore(m_profile->m_profileIOData->clientCertificateStoreData()); + return m_clientCertificateStore; +} +#endif + } // namespace QtWebEngineCore diff --git a/src/core/profile_adapter.h b/src/core/profile_adapter.h index e92fb524b..1f94f59a9 100644 --- a/src/core/profile_adapter.h +++ b/src/core/profile_adapter.h @@ -60,22 +60,25 @@ #include <QString> #include <QVector> +#include "api/qwebengineclientcertificatestore.h" #include "api/qwebenginecookiestore.h" #include "api/qwebengineurlrequestinterceptor.h" #include "api/qwebengineurlschemehandler.h" +#include "net/qrc_url_scheme_handler.h" QT_FORWARD_DECLARE_CLASS(QObject) namespace QtWebEngineCore { -class ProfileAdapterClient; +class UserNotificationController; class DownloadManagerDelegateQt; +class ProfileAdapterClient; class ProfileQt; class UserResourceControllerHost; class VisitedLinksManagerQt; class WebContentsAdapterClient; -class QWEBENGINECORE_PRIVATE_EXPORT ProfileAdapter : public QObject +class Q_WEBENGINECORE_PRIVATE_EXPORT ProfileAdapter : public QObject { public: explicit ProfileAdapter(const QString &storagePrefix = QString()); @@ -113,6 +116,9 @@ public: QString dataPath() const; void setDataPath(const QString &path); + QString downloadPath() const { return m_downloadPath; } + void setDownloadPath(const QString &path); + QString cachePath() const; void setCachePath(const QString &path); @@ -153,8 +159,7 @@ public: enum PermissionType { UnsupportedPermission = 0, GeolocationPermission = 1, -// Reserved: -// NotificationPermission = 2, + NotificationPermission = 2, AudioCapturePermission = 3, VideoCapturePermission = 4, ClipboardRead = 5, @@ -174,14 +179,14 @@ public: void setHttpCacheMaxSize(int maxSize); bool trackVisitedLinks() const; - bool persistVisitedLinks() const; - const QHash<QByteArray, QWebEngineUrlSchemeHandler *> &customUrlSchemeHandlers() const; + QWebEngineUrlSchemeHandler *urlSchemeHandler(const QByteArray &scheme); + void installUrlSchemeHandler(const QByteArray &scheme, QWebEngineUrlSchemeHandler *handler); + void removeUrlScheme(const QByteArray &scheme); + void removeUrlSchemeHandler(QWebEngineUrlSchemeHandler *handler); + void removeAllUrlSchemeHandlers(); + const QList<QByteArray> customUrlSchemes() const; - void clearCustomUrlSchemeHandlers(); - bool addCustomUrlSchemeHandler(const QByteArray &, QWebEngineUrlSchemeHandler *); - bool removeCustomUrlSchemeHandler(QWebEngineUrlSchemeHandler *); - QWebEngineUrlSchemeHandler *takeCustomUrlSchemeHandler(const QByteArray &); UserResourceControllerHost *userResourceController(); void permissionRequestReply(const QUrl &origin, PermissionType type, bool reply); @@ -193,30 +198,57 @@ public: void clearHttpCache(); + void setUseForGlobalCertificateVerification(bool enable = true); + bool isUsedForGlobalCertificateVerification() const; + + void addPageRequestInterceptor(); + void removePageRequestInterceptor(); + bool hasPageRequestInterceptor() const { return m_pageRequestInterceptors > 0; } + +#if QT_CONFIG(ssl) + QWebEngineClientCertificateStore *clientCertificateStore(); +#endif + + QHash<QByteArray, QWeakPointer<UserNotificationController>> &ephemeralNotifications() + { return m_ephemeralNotifications; } + QHash<QByteArray, QSharedPointer<UserNotificationController>> &persistentNotifications() + { return m_persistentNotifications; } + private: void updateCustomUrlSchemeHandlers(); void resetVisitedLinksManager(); + bool persistVisitedLinks() const; QString m_name; bool m_offTheRecord; + bool m_usedForGlobalCertificateVerification = false; QScopedPointer<ProfileQt> m_profile; QScopedPointer<VisitedLinksManagerQt> m_visitedLinksManager; QScopedPointer<DownloadManagerDelegateQt> m_downloadManagerDelegate; QScopedPointer<UserResourceControllerHost> m_userResourceController; QScopedPointer<QWebEngineCookieStore> m_cookieStore; +#if QT_CONFIG(ssl) + QWebEngineClientCertificateStore *m_clientCertificateStore = nullptr; +#endif QPointer<QWebEngineUrlRequestInterceptor> m_requestInterceptor; QString m_dataPath; + QString m_downloadPath; QString m_cachePath; QString m_httpUserAgent; HttpCacheType m_httpCacheType; QString m_httpAcceptLanguage; PersistentCookiesPolicy m_persistentCookiesPolicy; VisitedLinksPolicy m_visitedLinksPolicy; - QHash<QByteArray, QWebEngineUrlSchemeHandler *> m_customUrlSchemeHandlers; + QHash<QByteArray, QPointer<QWebEngineUrlSchemeHandler>> m_customUrlSchemeHandlers; + QHash<QByteArray, QWeakPointer<UserNotificationController>> m_ephemeralNotifications; + QHash<QByteArray, QSharedPointer<UserNotificationController>> m_persistentNotifications; + QList<ProfileAdapterClient*> m_clients; QVector<WebContentsAdapterClient *> m_webContentsAdapterClients; int m_httpCacheMaxSize; + int m_pageRequestInterceptors; + QrcUrlSchemeHandler m_qrcHandler; Q_DISABLE_COPY(ProfileAdapter) }; diff --git a/src/core/profile_adapter_client.h b/src/core/profile_adapter_client.h index 19af12ca4..b463043da 100644 --- a/src/core/profile_adapter_client.h +++ b/src/core/profile_adapter_client.h @@ -52,14 +52,16 @@ #define PROFILE_ADAPTER_CLIENT_H #include "qtwebenginecoreglobal_p.h" +#include <QSharedPointer> #include <QString> #include <QUrl> namespace QtWebEngineCore { class WebContentsAdapterClient; +class UserNotificationController; -class QWEBENGINECORE_PRIVATE_EXPORT ProfileAdapterClient +class Q_WEBENGINECORE_PRIVATE_EXPORT ProfileAdapterClient { public: // Keep in sync with content::DownloadItem::DownloadState @@ -142,6 +144,9 @@ public: virtual void downloadRequested(DownloadItemInfo &info) = 0; virtual void downloadUpdated(const DownloadItemInfo &info) = 0; + virtual void useForGlobalCertificateVerificationChanged() {} + virtual void showNotification(QSharedPointer<UserNotificationController> &) { } + virtual void addWebContentsAdapterClient(WebContentsAdapterClient *adapter) = 0; virtual void removeWebContentsAdapterClient(WebContentsAdapterClient *adapter) = 0; static QString downloadInterruptReasonToString(DownloadInterruptReason reason); diff --git a/src/core/profile_io_data_qt.cpp b/src/core/profile_io_data_qt.cpp index 99a6f6db0..27c97a986 100644 --- a/src/core/profile_io_data_qt.cpp +++ b/src/core/profile_io_data_qt.cpp @@ -39,9 +39,10 @@ #include "profile_io_data_qt.h" -#include "base/task_scheduler/post_task.h" +#include "base/task/post_task.h" #include "components/certificate_transparency/ct_known_logs.h" #include "components/network_session_configurator/common/network_features.h" +#include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/browsing_data_remover.h" #include "content/public/browser/cookie_store_factory.h" @@ -49,6 +50,7 @@ #include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h" #include "chrome/browser/net/chrome_mojo_proxy_resolver_factory.h" #include "chrome/common/chrome_switches.h" +#include "components/proxy_config/pref_proxy_config_tracker_impl.h" #include "net/cert/cert_verifier.h" #include "net/cert/ct_log_verifier.h" #include "net/cert/ct_policy_enforcer.h" @@ -77,16 +79,26 @@ #include "services/file/user_id_map.h" #include "services/network/proxy_service_mojo.h" +#include "net/client_cert_override.h" +#include "net/client_cert_store_data.h" #include "net/cookie_monster_delegate_qt.h" #include "net/custom_protocol_handler.h" #include "net/network_delegate_qt.h" #include "net/proxy_config_service_qt.h" -#include "net/qrc_protocol_handler_qt.h" #include "net/url_request_context_getter_qt.h" #include "profile_qt.h" #include "resource_context_qt.h" #include "type_conversion.h" +#if defined(USE_NSS_CERTS) +#include "net/cert_net/nss_ocsp.h" +#endif + +#if defined(OS_LINUX) || defined(OS_MACOSX) +#include "net/cert/cert_net_fetcher.h" +#include "net/cert_net/cert_net_fetcher_impl.h" +#endif + namespace QtWebEngineCore { static bool doNetworkSessionParamsMatch(const net::HttpNetworkSession::Params &first, @@ -96,8 +108,6 @@ static bool doNetworkSessionParamsMatch(const net::HttpNetworkSession::Params &f return false; if (first.enable_channel_id != second.enable_channel_id) return false; - if (first.enable_token_binding != second.enable_token_binding) - return false; return true; } @@ -147,14 +157,16 @@ static net::HttpNetworkSession::Params generateNetworkSessionParams(bool ignoreC { net::HttpNetworkSession::Params network_session_params; network_session_params.ignore_certificate_errors = ignoreCertificateErrors; - network_session_params.enable_token_binding = base::FeatureList::IsEnabled(features::kTokenBinding); - network_session_params.enable_channel_id = base::FeatureList::IsEnabled(features::kChannelID); return network_session_params; } ProfileIODataQt::ProfileIODataQt(ProfileQt *profile) : m_profile(profile), +#if QT_CONFIG(ssl) + m_clientCertificateStoreData(new ClientCertificateStoreData), +#endif m_mutex(QMutex::Recursive), + m_removerObserver(this), m_weakPtrFactory(this) { if (content::BrowserThread::IsThreadInitialized(content::BrowserThread::UI)) @@ -165,8 +177,19 @@ ProfileIODataQt::~ProfileIODataQt() { if (content::BrowserThread::IsThreadInitialized(content::BrowserThread::IO)) DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + + if (m_useForGlobalCertificateVerification) { +#if defined(USE_NSS_CERTS) + net::SetURLRequestContextForNSSHttpIO(nullptr); +#endif +#if defined(OS_LINUX) ||defined(OS_MACOSX) + net::ShutdownGlobalCertNetFetcher(); +#endif + } + if (m_urlRequestContext && m_urlRequestContext->proxy_resolution_service()) m_urlRequestContext->proxy_resolution_service()->OnShutdown(); + m_resourceContext.reset(); if (m_cookieDelegate) m_cookieDelegate->setCookieMonster(0); // this will let CookieMonsterDelegateQt be deleted @@ -174,9 +197,18 @@ ProfileIODataQt::~ProfileIODataQt() delete m_proxyConfigService.fetchAndStoreAcquire(0); } +QPointer<ProfileAdapter> ProfileIODataQt::profileAdapter() +{ + return m_profileAdapter; +} + void ProfileIODataQt::shutdownOnUIThread() { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); +#if QT_CONFIG(ssl) + delete m_clientCertificateStoreData; + m_clientCertificateStoreData = nullptr; +#endif bool posted = content::BrowserThread::DeleteSoon(content::BrowserThread::IO, FROM_HERE, this); if (!posted) { qWarning() << "Could not delete ProfileIODataQt on io thread !"; @@ -197,6 +229,13 @@ content::ResourceContext *ProfileIODataQt::resourceContext() return m_resourceContext.get(); } +#if BUILDFLAG(ENABLE_EXTENSIONS) +extensions::ExtensionSystemQt* ProfileIODataQt::GetExtensionSystem() +{ + return m_profile->GetExtensionSystem(); +} +#endif // BUILDFLAG(ENABLE_EXTENSIONS) + void ProfileIODataQt::initializeOnIOThread() { m_networkDelegate.reset(new NetworkDelegateQt(this)); @@ -210,6 +249,7 @@ void ProfileIODataQt::initializeOnIOThread() QMutexLocker lock(&m_mutex); generateAllStorage(); generateJobFactory(); + setGlobalCertificateVerification(); m_initialized = true; } @@ -276,7 +316,15 @@ void ProfileIODataQt::generateStorage() net::ProxyConfigService *proxyConfigService = m_proxyConfigService.fetchAndStoreAcquire(0); Q_ASSERT(proxyConfigService); - m_storage->set_cert_verifier(net::CertVerifier::CreateDefault()); + std::unique_ptr<net::CertVerifier> cert_verifier = net::CertVerifier::CreateDefault(); + net::CertVerifier::Config config; + // Enable revocation checking: + config.enable_rev_checking = true; + // Mirroring Android WebView (we have no beef with Symantec, and our users might use them): + config.disable_symantec_enforcement = true; + cert_verifier->SetConfig(config); + + m_storage->set_cert_verifier(std::move(cert_verifier)); std::unique_ptr<net::MultiLogCTVerifier> ct_verifier(new net::MultiLogCTVerifier()); std::vector<scoped_refptr<const net::CTLogVerifier>> ct_logs; for (const auto &ct_log : certificate_transparency::GetKnownLogs()) { @@ -306,7 +354,7 @@ void ProfileIODataQt::generateStorage() scoped_refptr<base::SequencedTaskRunner> background_task_runner( base::CreateSequencedTaskRunnerWithTraits( {base::MayBlock(), - base::TaskPriority::BACKGROUND, + base::TaskPriority::BEST_EFFORT, base::TaskShutdownBehavior::BLOCK_SHUTDOWN})); m_transportSecurityPersister = std::make_unique<net::TransportSecurityPersister>( @@ -347,7 +395,7 @@ void ProfileIODataQt::generateCookieStore() channel_id_db = new net::SQLiteChannelIDStore( toFilePath(m_channelIdPath), base::CreateSequencedTaskRunnerWithTraits( - {base::MayBlock(), base::TaskPriority::BACKGROUND})); + {base::MayBlock(), base::TaskPriority::BEST_EFFORT})); } m_storage->set_channel_id_service( @@ -362,8 +410,8 @@ void ProfileIODataQt::generateCookieStore() base::FilePath(), false, false, - nullptr) - ); + nullptr), + nullptr); break; case ProfileAdapter::AllowPersistentCookies: cookieStore = content::CreateCookieStore( @@ -371,8 +419,8 @@ void ProfileIODataQt::generateCookieStore() toFilePath(m_cookiesPath), false, true, - nullptr) - ); + nullptr), + nullptr); break; case ProfileAdapter::ForcePersistentCookies: cookieStore = content::CreateCookieStore( @@ -380,8 +428,8 @@ void ProfileIODataQt::generateCookieStore() toFilePath(m_cookiesPath), true, true, - nullptr) - ); + nullptr), + nullptr); break; } @@ -391,7 +439,7 @@ void ProfileIODataQt::generateCookieStore() m_storage->set_cookie_store(std::move(cookieStore)); const std::vector<std::string> cookieableSchemes(kCookieableSchemes, - kCookieableSchemes + arraysize(kCookieableSchemes)); + kCookieableSchemes + base::size(kCookieableSchemes)); cookieMonster->SetCookieableSchemes(cookieableSchemes); } @@ -478,13 +526,10 @@ void ProfileIODataQt::generateJobFactory() std::unique_ptr<net::URLRequestJobFactory::ProtocolHandler>( new net::DataProtocolHandler())); scoped_refptr<base::TaskRunner> taskRunner(base::CreateTaskRunnerWithTraits({base::MayBlock(), - base::TaskPriority::BACKGROUND, + base::TaskPriority::BEST_EFFORT, base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN})); jobFactory->SetProtocolHandler(url::kFileScheme, std::make_unique<net::FileProtocolHandler>(taskRunner)); - jobFactory->SetProtocolHandler(kQrcSchemeQt, - std::unique_ptr<net::URLRequestJobFactory::ProtocolHandler>( - new QrcProtocolHandlerQt())); jobFactory->SetProtocolHandler(url::kFtpScheme, net::FtpProtocolHandler::Create(m_urlRequestContext->host_resolver())); @@ -542,6 +587,21 @@ void ProfileIODataQt::regenerateJobFactory() } } +void ProfileIODataQt::setGlobalCertificateVerification() +{ + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); + QMutexLocker lock(&m_mutex); + if (m_useForGlobalCertificateVerification) { +#if defined(USE_NSS_CERTS) + // Set request context used by NSS for OCSP requests. + net::SetURLRequestContextForNSSHttpIO(m_urlRequestContext.get()); +#endif +#if defined(OS_LINUX) || defined(OS_MACOSX) + net::SetGlobalCertNetFetcher(net::CreateCertNetFetcher(m_urlRequestContext.get())); +#endif + } +} + void ProfileIODataQt::setRequestContextData(content::ProtocolHandlerMap *protocolHandlers, content::URLRequestInterceptorScopedVector request_interceptors) { @@ -564,6 +624,7 @@ void ProfileIODataQt::setFullConfiguration() m_httpCachePath = m_profileAdapter->httpCachePath(); m_httpCacheMaxSize = m_profileAdapter->httpCacheMaxSize(); m_customUrlSchemes = m_profileAdapter->customUrlSchemes(); + m_useForGlobalCertificateVerification = m_profileAdapter->isUsedForGlobalCertificateVerification(); m_dataPath = m_profileAdapter->dataPath(); } @@ -573,8 +634,8 @@ void ProfileIODataQt::requestStorageGeneration() { if (m_initialized && !m_updateAllStorage) { m_updateAllStorage = true; createProxyConfig(); - content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, - base::Bind(&ProfileIODataQt::generateAllStorage, m_weakPtr)); + base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::IO}, + base::BindOnce(&ProfileIODataQt::generateAllStorage, m_weakPtr)); } } @@ -587,10 +648,14 @@ void ProfileIODataQt::createProxyConfig() // must synchronously run on the glib message loop. This will be passed to // the URLRequestContextStorage on the IO thread in GetURLRequestContext(). Q_ASSERT(m_proxyConfigService == 0); + net::ProxyConfigWithAnnotation initialConfig; + ProxyPrefs::ConfigState initialConfigState = PrefProxyConfigTrackerImpl::ReadPrefConfig( + m_profileAdapter->profile()->GetPrefs(), &initialConfig); m_proxyConfigService = new ProxyConfigServiceQt( net::ProxyResolutionService::CreateSystemProxyConfigService( - content::BrowserThread::GetTaskRunnerForThread(content::BrowserThread::IO))); + base::CreateSingleThreadTaskRunnerWithTraits({content::BrowserThread::IO})), + initialConfig, initialConfigState); //pass interface to io thread m_proxyResolverFactoryInterface = ChromeMojoProxyResolverFactory::CreateWithStrongBinding().PassInterface(); } @@ -602,12 +667,13 @@ void ProfileIODataQt::updateStorageSettings() QMutexLocker lock(&m_mutex); setFullConfiguration(); - std::string userId = content::BrowserContext::GetServiceUserIdFor(m_profile); - if (file::GetUserDirForUserId(userId) != toFilePath(m_profileAdapter->dataPath())) { - file::ForgetServiceUserIdUserDirAssociation(userId); - file::AssociateServiceUserIdWithUserDir(userId, toFilePath(m_profileAdapter->dataPath())); + base::Token groupId = content::BrowserContext::GetServiceInstanceGroupFor(m_profile); + if (file::GetUserDirForInstanceGroup(groupId) != toFilePath(m_profileAdapter->dataPath())) { + file::ForgetServiceInstanceGroupUserDirAssociation(groupId); + file::AssociateServiceInstanceGroupWithUserDir(groupId, toFilePath(m_profileAdapter->dataPath())); } - requestStorageGeneration(); + if (!m_pendingStorageRequestGeneration) + requestStorageGeneration(); } void ProfileIODataQt::updateCookieStore() @@ -617,7 +683,8 @@ void ProfileIODataQt::updateCookieStore() m_persistentCookiesPolicy = m_profileAdapter->persistentCookiesPolicy(); m_cookiesPath = m_profileAdapter->cookiesPath(); m_channelIdPath = m_profileAdapter->channelIdPath(); - requestStorageGeneration(); + if (!m_pendingStorageRequestGeneration) + requestStorageGeneration(); } void ProfileIODataQt::updateUserAgent() @@ -626,7 +693,8 @@ void ProfileIODataQt::updateUserAgent() QMutexLocker lock(&m_mutex); m_httpAcceptLanguage = m_profileAdapter->httpAcceptLanguage(); m_httpUserAgent = m_profileAdapter->httpUserAgent(); - requestStorageGeneration(); + if (!m_pendingStorageRequestGeneration) + requestStorageGeneration(); } void ProfileIODataQt::updateHttpCache() @@ -638,14 +706,19 @@ void ProfileIODataQt::updateHttpCache() m_httpCacheMaxSize = m_profileAdapter->httpCacheMaxSize(); if (m_httpCacheType == ProfileAdapter::NoCache) { + m_pendingStorageRequestGeneration = true; content::BrowsingDataRemover *remover = content::BrowserContext::GetBrowsingDataRemover(m_profileAdapter->profile()); - remover->Remove(base::Time(), base::Time::Max(), + remover->AddObserver(&m_removerObserver); + remover->RemoveAndReply(base::Time(), base::Time::Max(), content::BrowsingDataRemover::DATA_TYPE_CACHE, content::BrowsingDataRemover::ORIGIN_TYPE_UNPROTECTED_WEB | - content::BrowsingDataRemover::ORIGIN_TYPE_PROTECTED_WEB); + content::BrowsingDataRemover::ORIGIN_TYPE_PROTECTED_WEB, + &m_removerObserver); + return; } - requestStorageGeneration(); + if (!m_pendingStorageRequestGeneration) + requestStorageGeneration(); } void ProfileIODataQt::updateJobFactory() @@ -657,8 +730,8 @@ void ProfileIODataQt::updateJobFactory() if (m_initialized && !m_updateJobFactory) { m_updateJobFactory = true; - content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, - base::Bind(&ProfileIODataQt::regenerateJobFactory, m_weakPtr)); + base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::IO}, + base::BindOnce(&ProfileIODataQt::regenerateJobFactory, m_weakPtr)); } } @@ -667,6 +740,7 @@ void ProfileIODataQt::updateRequestInterceptor() Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); QMutexLocker lock(&m_mutex); m_requestInterceptor = m_profileAdapter->requestInterceptor(); + m_hasPageInterceptors = m_profileAdapter->hasPageRequestInterceptor(); // We in this case do not need to regenerate any Chromium classes. } @@ -676,6 +750,18 @@ QWebEngineUrlRequestInterceptor *ProfileIODataQt::acquireInterceptor() return m_requestInterceptor; } +QWebEngineUrlRequestInterceptor *ProfileIODataQt::requestInterceptor() +{ + return m_requestInterceptor; +} + +bool ProfileIODataQt::hasPageInterceptors() +{ + // used in NetworkDelegateQt::OnBeforeURLRequest + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); + return m_hasPageInterceptors; +} + void ProfileIODataQt::releaseInterceptor() { m_mutex.unlock(); @@ -691,4 +777,57 @@ bool ProfileIODataQt::canGetCookies(const QUrl &firstPartyUrl, const QUrl &url) return m_cookieDelegate->canGetCookies(firstPartyUrl, url); } +void ProfileIODataQt::updateUsedForGlobalCertificateVerification() +{ + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + QMutexLocker lock(&m_mutex); + m_useForGlobalCertificateVerification = m_profileAdapter->isUsedForGlobalCertificateVerification(); + + if (m_useForGlobalCertificateVerification) + base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::IO}, + base::BindOnce(&ProfileIODataQt::setGlobalCertificateVerification, m_weakPtr)); +} + +#if QT_CONFIG(ssl) +ClientCertificateStoreData *ProfileIODataQt::clientCertificateStoreData() +{ + return m_clientCertificateStoreData; +} +#endif + +std::unique_ptr<net::ClientCertStore> ProfileIODataQt::CreateClientCertStore() +{ +#if QT_CONFIG(ssl) + return std::unique_ptr<net::ClientCertStore>(new ClientCertOverrideStore(m_clientCertificateStoreData)); +#else + return nullptr; +#endif +} + +// static +ProfileIODataQt *ProfileIODataQt::FromResourceContext(content::ResourceContext *resource_context) +{ + return static_cast<ResourceContextQt *>(resource_context)->m_io_data; +} + +void ProfileIODataQt::removeBrowsingDataRemoverObserver() +{ + content::BrowsingDataRemover *remover = + content::BrowserContext::GetBrowsingDataRemover(m_profileAdapter->profile()); + remover->RemoveObserver(&m_removerObserver); +} + +BrowsingDataRemoverObserverQt::BrowsingDataRemoverObserverQt(ProfileIODataQt *profileIOData) + : m_profileIOData(profileIOData) +{ +} + +void BrowsingDataRemoverObserverQt::OnBrowsingDataRemoverDone() +{ + Q_ASSERT(m_profileIOData->m_pendingStorageRequestGeneration); + m_profileIOData->requestStorageGeneration(); + m_profileIOData->removeBrowsingDataRemoverObserver(); + m_profileIOData->m_pendingStorageRequestGeneration = false; +} + } // namespace QtWebEngineCore diff --git a/src/core/profile_io_data_qt.h b/src/core/profile_io_data_qt.h index 8ce6185b5..570365085 100644 --- a/src/core/profile_io_data_qt.h +++ b/src/core/profile_io_data_qt.h @@ -41,8 +41,10 @@ #define PROFILE_IO_DATA_QT_H #include "profile_adapter.h" +#include "content/public/browser/browsing_data_remover.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/custom_handlers/protocol_handler_registry.h" +#include "extensions/buildflags/buildflags.h" #include "services/proxy_resolver/public/mojom/proxy_resolver.mojom.h" #include <QtCore/QString> @@ -50,6 +52,7 @@ #include <QtCore/QMutex> namespace net { +class ClientCertStore; class DhcpPacFileFetcherFactory; class HttpAuthPreferences; class HttpNetworkSession; @@ -61,10 +64,28 @@ class URLRequestJobFactoryImpl; class TransportSecurityPersister; } +namespace extensions { +class ExtensionSystemQt; +} + namespace QtWebEngineCore { +struct ClientCertificateStoreData; +class ProfileIODataQt; class ProfileQt; + +class BrowsingDataRemoverObserverQt : public content::BrowsingDataRemover::Observer { +public: + BrowsingDataRemoverObserverQt(ProfileIODataQt *profileIOData); + + void OnBrowsingDataRemoverDone() override; + +private: + ProfileIODataQt *m_profileIOData; +}; + + // ProfileIOData contains data that lives on the IOthread // we still use shared memebers and use mutex which breaks // idea for this object, but this is wip. @@ -75,8 +96,13 @@ public: ProfileIODataQt(ProfileQt *profile); // runs on ui thread virtual ~ProfileIODataQt(); + QPointer<ProfileAdapter> profileAdapter(); content::ResourceContext *resourceContext(); net::URLRequestContext *urlRequestContext(); +#if BUILDFLAG(ENABLE_EXTENSIONS) + extensions::ExtensionSystemQt* GetExtensionSystem(); +#endif // BUILDFLAG(ENABLE_EXTENSIONS) + void initializeOnIOThread(); void initializeOnUIThread(); // runs on ui thread void shutdownOnUIThread(); // runs on ui thread @@ -91,10 +117,12 @@ public: void regenerateJobFactory(); bool canSetCookie(const QUrl &firstPartyUrl, const QByteArray &cookieLine, const QUrl &url) const; bool canGetCookies(const QUrl &firstPartyUrl, const QUrl &url) const; + void setGlobalCertificateVerification(); // Used in NetworkDelegateQt::OnBeforeURLRequest. QWebEngineUrlRequestInterceptor *acquireInterceptor(); void releaseInterceptor(); + QWebEngineUrlRequestInterceptor *requestInterceptor(); void setRequestContextData(content::ProtocolHandlerMap *protocolHandlers, content::URLRequestInterceptorScopedVector request_interceptors); @@ -107,8 +135,17 @@ public: void updateRequestInterceptor(); // runs on ui thread void requestStorageGeneration(); //runs on ui thread void createProxyConfig(); //runs on ui thread + void updateUsedForGlobalCertificateVerification(); // runs on ui thread + bool hasPageInterceptors(); +#if QT_CONFIG(ssl) + ClientCertificateStoreData *clientCertificateStoreData(); +#endif + std::unique_ptr<net::ClientCertStore> CreateClientCertStore(); + static ProfileIODataQt *FromResourceContext(content::ResourceContext *resource_context); private: + void removeBrowsingDataRemoverObserver(); + ProfileQt *m_profile; std::unique_ptr<net::URLRequestContextStorage> m_storage; std::unique_ptr<net::NetworkDelegate> m_networkDelegate; @@ -130,6 +167,9 @@ private: QAtomicPointer<net::ProxyConfigService> m_proxyConfigService; QPointer<ProfileAdapter> m_profileAdapter; // never dereferenced in IO thread and it is passed by qpointer ProfileAdapter::PersistentCookiesPolicy m_persistentCookiesPolicy; +#if QT_CONFIG(ssl) + ClientCertificateStoreData *m_clientCertificateStoreData; +#endif QString m_cookiesPath; QString m_channelIdPath; QString m_httpAcceptLanguage; @@ -145,9 +185,15 @@ private: bool m_updateAllStorage = false; bool m_updateJobFactory = false; bool m_ignoreCertificateErrors = false; + bool m_useForGlobalCertificateVerification = false; + bool m_hasPageInterceptors = false; + BrowsingDataRemoverObserverQt m_removerObserver; base::WeakPtrFactory<ProfileIODataQt> m_weakPtrFactory; // this should be always the last member QString m_dataPath; + bool m_pendingStorageRequestGeneration = false; DISALLOW_COPY_AND_ASSIGN(ProfileIODataQt); + + friend class BrowsingDataRemoverObserverQt; }; } // namespace QtWebEngineCore diff --git a/src/core/profile_qt.cpp b/src/core/profile_qt.cpp index 2387eba1b..5977a28a8 100644 --- a/src/core/profile_qt.cpp +++ b/src/core/profile_qt.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtWebEngine module of the Qt Toolkit. @@ -41,6 +41,7 @@ #include "profile_adapter.h" #include "browsing_data_remover_delegate_qt.h" +#include "command_line_pref_store_qt.h" #include "download_manager_delegate_qt.h" #include "net/ssl_host_state_delegate_qt.h" #include "net/url_request_context_getter_qt.h" @@ -48,9 +49,11 @@ #include "qtwebenginecoreglobal_p.h" #include "type_conversion.h" #include "web_engine_library_info.h" +#include "web_engine_context.h" #include "base/time/time.h" #include "content/public/browser/browser_thread.h" +#include "content/public/browser/shared_cors_origin_access_list.h" #include "content/public/browser/storage_partition.h" #include "base/base_paths.h" @@ -62,22 +65,39 @@ #include "components/prefs/pref_service_factory.h" #include "components/prefs/pref_registry_simple.h" #include "components/user_prefs/user_prefs.h" +#include "components/proxy_config/pref_proxy_config_tracker_impl.h" +#include "chrome/common/pref_names.h" #if QT_CONFIG(webengine_spellchecker) #include "chrome/browser/spellchecker/spellcheck_service.h" -#include "chrome/common/pref_names.h" #include "components/spellcheck/browser/pref_names.h" #endif +#if BUILDFLAG(ENABLE_EXTENSIONS) +#include "components/guest_view/browser/guest_view_manager.h" +#include "extensions/browser/extension_protocols.h" +#include "extensions/browser/pref_names.h" +#include "extensions/browser/process_manager.h" +#include "extensions/common/constants.h" + +#include "extensions/extension_system_qt.h" +#endif + namespace QtWebEngineCore { ProfileQt::ProfileQt(ProfileAdapter *profileAdapter) - : m_profileIOData(new ProfileIODataQt(this)), - m_profileAdapter(profileAdapter) + : m_sharedCorsOriginAccessList(content::SharedCorsOriginAccessList::Create()) + , m_profileIOData(new ProfileIODataQt(this)) + , m_profileAdapter(profileAdapter) +#if BUILDFLAG(ENABLE_EXTENSIONS) + , m_extensionSystem(nullptr) +#endif // BUILDFLAG(ENABLE_EXTENSIONS) { PrefServiceFactory factory; factory.set_user_prefs(new InMemoryPrefStore); + factory.set_command_line_prefs(base::MakeRefCounted<CommandLinePrefStoreQt>( + WebEngineContext::commandLine())); PrefRegistrySimple *registry = new PrefRegistrySimple(); - + PrefProxyConfigTrackerImpl::RegisterPrefs(registry); #if QT_CONFIG(webengine_spellchecker) // Initial spellcheck settings registry->RegisterStringPref(prefs::kAcceptLanguages, std::string()); @@ -87,6 +107,24 @@ ProfileQt::ProfileQt(ProfileAdapter *profileAdapter) registry->RegisterBooleanPref(spellcheck::prefs::kSpellCheckEnable, false); registry->RegisterBooleanPref(spellcheck::prefs::kSpellCheckUseSpellingService, false); #endif // QT_CONFIG(webengine_spellchecker) + registry->RegisterBooleanPref(prefs::kShowInternalAccessibilityTree, false); + registry->RegisterIntegerPref(prefs::kNotificationNextPersistentId, 10000); + +#if BUILDFLAG(ENABLE_EXTENSIONS) + registry->RegisterDictionaryPref(extensions::pref_names::kExtensions); + registry->RegisterListPref(extensions::pref_names::kInstallAllowList); + registry->RegisterListPref(extensions::pref_names::kInstallDenyList); + registry->RegisterDictionaryPref(extensions::pref_names::kInstallForceList); + registry->RegisterDictionaryPref(extensions::pref_names::kInstallLoginScreenAppList); + registry->RegisterListPref(extensions::pref_names::kAllowedTypes); + registry->RegisterBooleanPref(extensions::pref_names::kStorageGarbageCollect, false); + registry->RegisterListPref(extensions::pref_names::kAllowedInstallSites); + registry->RegisterStringPref(extensions::pref_names::kLastChromeVersion, std::string()); + registry->RegisterListPref(extensions::pref_names::kNativeMessagingBlacklist); + registry->RegisterListPref(extensions::pref_names::kNativeMessagingWhitelist); + registry->RegisterBooleanPref(extensions::pref_names::kNativeMessagingUserLevelHosts, true); +#endif // BUILDFLAG(ENABLE_EXTENSIONS) + m_prefService = factory.Create(registry); user_prefs::UserPrefs::Set(this, m_prefService.get()); @@ -95,6 +133,11 @@ ProfileQt::ProfileQt(ProfileAdapter *profileAdapter) // ProfileQt object is allocated at the same address as a previously // destroyed one. Needs to be called after WebEngineContext initialization. BrowserContextDependencyManager::GetInstance()->MarkBrowserContextLive(this); + +#if BUILDFLAG(ENABLE_EXTENSIONS) + m_extensionSystem = static_cast<extensions::ExtensionSystemQt*>(extensions::ExtensionSystem::Get(this)); + m_extensionSystem->InitForRegularProfile(true); +#endif } ProfileQt::~ProfileQt() @@ -123,6 +166,11 @@ base::FilePath ProfileQt::GetPath() const return toFilePath(m_profileAdapter->dataPath()); } +base::FilePath ProfileQt::GetCachePath() const +{ + return toFilePath(m_profileAdapter->cachePath()); +} + bool ProfileQt::IsOffTheRecord() const { return m_profileAdapter->isOffTheRecord(); @@ -156,7 +204,11 @@ content::DownloadManagerDelegate *ProfileQt::GetDownloadManagerDelegate() content::BrowserPluginGuestManager *ProfileQt::GetGuestManager() { +#if BUILDFLAG(ENABLE_EXTENSIONS) + return guest_view::GuestViewManager::FromBrowserContext(this); +#else return nullptr; +#endif } storage::SpecialStoragePolicy *ProfileQt::GetSpecialStoragePolicy() @@ -212,6 +264,12 @@ net::URLRequestContextGetter *ProfileQt::CreateRequestContext( { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK(!m_urlRequestContextGetter.get()); +#if BUILDFLAG(ENABLE_EXTENSIONS) + extensions::InfoMap* extension_info_map = GetExtensionSystem()->info_map(); + (*protocol_handlers)[extensions::kExtensionScheme] = + extensions::CreateExtensionProtocolHandler(IsOffTheRecord(),extension_info_map); +#endif + m_profileIOData->setRequestContextData(protocol_handlers, std::move(request_interceptors)); m_profileIOData->updateStorageSettings(); m_urlRequestContextGetter = new URLRequestContextGetterQt(m_profileIOData.get()); @@ -227,12 +285,33 @@ net::URLRequestContextGetter *ProfileQt::CreateRequestContextForStoragePartition return nullptr; } +content::ClientHintsControllerDelegate *ProfileQt::GetClientHintsControllerDelegate() +{ + return nullptr; +} + +void ProfileQt::SetCorsOriginAccessListForOrigin(const url::Origin &source_origin, + std::vector<network::mojom::CorsOriginPatternPtr> allow_patterns, + std::vector<network::mojom::CorsOriginPatternPtr> block_patterns, + base::OnceClosure closure) +{ + m_sharedCorsOriginAccessList->SetForOrigin(source_origin, + std::move(allow_patterns), + std::move(block_patterns), + std::move(closure)); +} + +const content::SharedCorsOriginAccessList *ProfileQt::GetSharedCorsOriginAccessList() const +{ + return m_sharedCorsOriginAccessList.get(); +} + #if QT_CONFIG(webengine_spellchecker) void ProfileQt::FailedToLoadDictionary(const std::string &language) { Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); - qWarning() << "Could not load dictionary for:" << toQt(language) << endl - << "Make sure that correct bdic file is in:" << toQt(WebEngineLibraryInfo::getPath(base::DIR_APP_DICTIONARIES).value()); + LOG(WARNING) << "Could not load dictionary for:" << language; + LOG(INFO) << "Make sure that correct bdic file is in:" << WebEngineLibraryInfo::getPath(base::DIR_APP_DICTIONARIES); } void ProfileQt::setSpellCheckLanguages(const QStringList &languages) @@ -268,4 +347,12 @@ bool ProfileQt::isSpellCheckEnabled() const return m_prefService->GetBoolean(spellcheck::prefs::kSpellCheckEnable); } #endif // QT_CONFIG(webengine_spellchecker) + +#if BUILDFLAG(ENABLE_EXTENSIONS) +extensions::ExtensionSystemQt* ProfileQt::GetExtensionSystem() +{ + return m_extensionSystem; +} +#endif // BUILDFLAG(ENABLE_EXTENSIONS) + } // namespace QtWebEngineCore diff --git a/src/core/profile_qt.h b/src/core/profile_qt.h index b25ea047b..704c5a6e4 100644 --- a/src/core/profile_qt.h +++ b/src/core/profile_qt.h @@ -43,6 +43,7 @@ #include "chrome/browser/profiles/profile.h" #include "content/public/browser/content_browser_client.h" #include "content/public/browser/resource_context.h" +#include "extensions/buildflags/buildflags.h" #include "net/url_request/url_request_context.h" #include "profile_io_data_qt.h" #include <QtGlobal> @@ -53,6 +54,10 @@ QT_END_NAMESPACE class InMemoryPrefStore; class PrefService; +namespace extensions { +class ExtensionSystemQt; +} + namespace QtWebEngineCore { class BrowsingDataRemoverDelegateQt; @@ -67,6 +72,8 @@ public: virtual ~ProfileQt(); + base::FilePath GetCachePath() const; + // BrowserContext implementation: base::FilePath GetPath() const override; bool IsOffTheRecord() const override; @@ -94,11 +101,18 @@ public: content::BackgroundFetchDelegate *GetBackgroundFetchDelegate() override; content::BackgroundSyncController *GetBackgroundSyncController() override; content::BrowsingDataRemoverDelegate *GetBrowsingDataRemoverDelegate() override; + content::ClientHintsControllerDelegate *GetClientHintsControllerDelegate() override; + void SetCorsOriginAccessListForOrigin(const url::Origin &source_origin, + std::vector<network::mojom::CorsOriginPatternPtr> allow_patterns, + std::vector<network::mojom::CorsOriginPatternPtr> block_patterns, + base::OnceClosure closure) override; + const content::SharedCorsOriginAccessList* GetSharedCorsOriginAccessList() const override; // Profile implementation: PrefService *GetPrefs() override; const PrefService *GetPrefs() const override; net::URLRequestContextGetter *GetRequestContext() override; + void Initialize(); ProfileAdapter *profileAdapter() { return m_profileAdapter; } @@ -109,6 +123,9 @@ public: void setSpellCheckEnabled(bool enabled); bool isSpellCheckEnabled() const; #endif +#if BUILDFLAG(ENABLE_EXTENSIONS) + extensions::ExtensionSystemQt* GetExtensionSystem(); +#endif // defined(ENABLE_EXTENSIONS) private: friend class ContentBrowserClientQt; @@ -118,9 +135,14 @@ private: std::unique_ptr<PermissionManagerQt> m_permissionManager; std::unique_ptr<SSLHostStateDelegateQt> m_sslHostStateDelegate; std::unique_ptr<PrefService> m_prefService; + scoped_refptr<content::SharedCorsOriginAccessList> m_sharedCorsOriginAccessList; std::unique_ptr<ProfileIODataQt> m_profileIOData; ProfileAdapter *m_profileAdapter; friend class ProfileAdapter; +#if BUILDFLAG(ENABLE_EXTENSIONS) + extensions::ExtensionSystemQt *m_extensionSystem; +#endif //ENABLE_EXTENSIONS + friend class BrowserContextAdapter; DISALLOW_COPY_AND_ASSIGN(ProfileQt); }; diff --git a/src/core/qtwebengine.gni b/src/core/qtwebengine.gni index 14da1e6cf..11a72a2e9 100644 --- a/src/core/qtwebengine.gni +++ b/src/core/qtwebengine.gni @@ -1,6 +1,8 @@ import("//build/config/ui.gni") import("//media/media_options.gni") +import("//extensions/buildflags/buildflags.gni") import("//third_party/widevine/cdm/widevine.gni") +import("//ui/ozone/ozone.gni") chromium_version = exec_script("//build/util/version.py", [ "-f", rebase_path("//chrome/VERSION"), "-t", "@MAJOR@.@MINOR@.@BUILD@.@PATCH@"], @@ -9,6 +11,7 @@ chromium_version = exec_script("//build/util/version.py", [ "-f", rebase_path("/ include_dirs = [ "//skia/config", "//third_party", + "//third_party/boringssl/src/include", "//third_party/skia/include/core" ] @@ -25,37 +28,45 @@ deps = [ "//components/web_cache/browser", "//components/web_cache/renderer", "//components/spellcheck:buildflags", + "//components/proxy_config", "//content/public/app:browser", - "//content/public/browser", - "//content/public/common", - "//content/public/renderer", + "//content", "//media:media_buildflags", "//net:net_with_v8", "//services/proxy_resolver:lib", "//skia", "//third_party/blink/public:blink", - "//third_party/mesa:mesa_headers", "//ui/accessibility", + "//ui/gl", "//qtwebengine/browser:interfaces", + "//qtwebengine/browser:service_manifests", + "//qtwebengine/common:mojo_bindings", ":qtwebengine_sources", - ":qtwebengine_resources" + ":qtwebengine_resources", ] if (enable_webrtc) { deps += [ "//third_party/webrtc_overrides" ] } -if (is_linux && !is_desktop_linux) { - deps += [ "//ui/events/ozone:events_ozone_evdev"] +if (use_ozone) { + _ozone_extra_directory = get_path_info(ozone_extra_path, "dir") + deps += [ "$_ozone_extra_directory:qt" ] } -if (use_ozone) { +if (use_xscrnsaver) { + deps += [ "//ui/base/x" ] +} + +if (enable_extensions) { deps += [ - "//ui/ozone/common" + ":qtwebengine_extensions_features" ] } -data_deps = [ "//qtwebengine/browser:service_manifests" ] +assert_no_deps = [ + "//ui/views/mus", +] defines = [ "CHROMIUM_VERSION=\"" + chromium_version[0] + "\"" diff --git a/src/core/qtwebengine_resources.gni b/src/core/qtwebengine_resources.gni index 6e8c3c6eb..4df1760da 100644 --- a/src/core/qtwebengine_resources.gni +++ b/src/core/qtwebengine_resources.gni @@ -1,10 +1,14 @@ import("//tools/grit/repack.gni") import("//build/config/locales.gni") import("//chrome/chrome_repack_locales.gni") +import("//extensions/buildflags/buildflags.gni") group("qtwebengine_resources") { deps = [ "//chrome/app:generated_resources", + "//chrome/browser:resources", + "//chrome/browser/resources:component_extension_resources", + "//chrome/common:resources", "//components/resources:components_resources", ":qtwebengine_repack_resources", ":qtwebengine_repack_resources_100", @@ -17,6 +21,8 @@ group("qtwebengine_resources") { repack("qtwebengine_repack_resources") { sources = [ "$root_gen_dir/qtwebengine/qt_webengine_resources.pak", + "$root_gen_dir/chrome/browser_resources.pak", + "$root_gen_dir/chrome/common_resources.pak", "$root_gen_dir/chrome/quota_internals_resources.pak", "$root_gen_dir/chrome/task_scheduler_internals_resources.pak", "$root_gen_dir/components/components_resources.pak", @@ -31,6 +37,8 @@ repack("qtwebengine_repack_resources") { "//qtwebengine/browser:qt_webengine_resources", "//chrome/browser/resources:quota_internals_resources", "//chrome/browser/resources:task_scheduler_internals_resources", + "//chrome/browser:resources_grit", + "//chrome/common:resources_grit", "//components/resources:components_resources_grit", "//content:resources_grit", "//mojo/public/js:resources", @@ -38,6 +46,20 @@ repack("qtwebengine_repack_resources") { "//third_party/blink/public:resources_grit", "//ui/resources:webui_resources_grd_grit", ] + + if (enable_extensions) { + sources += [ + "$root_gen_dir/chrome/component_extension_resources.pak", + "$root_gen_dir/extensions/extensions_renderer_resources.pak", + "$root_gen_dir/extensions/extensions_resources.pak", + ] + deps += [ + "//chrome/browser/resources:component_extension_resources_grit", + "//extensions:extensions_renderer_resources_grit", + "//extensions:extensions_resources_grd_grit", + ] + } + } repack("qtwebengine_repack_resources_100") { @@ -56,6 +78,14 @@ repack("qtwebengine_repack_resources_100") { "//third_party/blink/public:scaled_resources_100_percent", "//ui/resources:ui_resources_grd_grit" ] + if (enable_extensions) { + sources += [ + "$root_gen_dir/extensions/extensions_browser_resources_100_percent.pak" + ] + deps += [ + "//extensions:extensions_browser_resources_grit" + ] + } } repack("qtwebengine_repack_resources_200") { @@ -74,6 +104,14 @@ repack("qtwebengine_repack_resources_200") { "//third_party/blink/public:scaled_resources_200_percent", "//ui/resources:ui_resources_grd_grit" ] + if (enable_extensions) { + sources += [ + "$root_gen_dir/extensions/extensions_browser_resources_200_percent.pak" + ] + deps += [ + "//extensions:extensions_browser_resources_grit" + ] + } } repack("qtwebengine_repack_resources_devtools") { @@ -82,7 +120,7 @@ repack("qtwebengine_repack_resources_devtools") { ] output = "$root_out_dir/qtwebengine_devtools_resources.pak" deps = [ - "//content/browser/devtools:devtools_resources_grit" + "//content/browser/devtools:devtools_resources_grit", ] } diff --git a/src/core/qtwebengine_sources.gni b/src/core/qtwebengine_sources.gni index b1361e727..58df7096b 100644 --- a/src/core/qtwebengine_sources.gni +++ b/src/core/qtwebengine_sources.gni @@ -1,9 +1,11 @@ import("//build/config/features.gni") import("//build/config/ui.gni") +import("//chrome/common/features.gni") import("//components/spellcheck/spellcheck_build_features.gni") import("//pdf/features.gni") import("//ppapi/buildflags/buildflags.gni") import("//printing/buildflags/buildflags.gni") +import("//extensions/buildflags/buildflags.gni") source_set("qtwebengine_spellcheck_sources") { include_dirs = core_include_dirs @@ -40,22 +42,22 @@ source_set("qtwebengine_sources") { "//skia:skia_config", "//third_party/boringssl:external_config", ] + deps = [ "//chrome/common:buildflags", "//components/nacl/common:buildflags", "//extensions/buildflags:buildflags", "//third_party/blink/public/mojom:mojom_platform", ] + sources = [ - "//chrome/common/custom_handlers/protocol_handler.cc", - "//chrome/common/custom_handlers/protocol_handler.h", + "//chrome/browser/accessibility/accessibility_ui.cc", + "//chrome/browser/accessibility/accessibility_ui.h", "//chrome/browser/custom_handlers/protocol_handler_registry.cc", "//chrome/browser/custom_handlers/protocol_handler_registry.h", "//chrome/browser/custom_handlers/protocol_handler_registry_factory.cc", "//chrome/browser/custom_handlers/protocol_handler_registry_factory.h", "//chrome/browser/media/webrtc/desktop_media_list.h", - "//chrome/browser/media/webrtc/desktop_streams_registry.cc", - "//chrome/browser/media/webrtc/desktop_streams_registry.h", "//chrome/browser/net/chrome_mojo_proxy_resolver_factory.cc", "//chrome/browser/net/chrome_mojo_proxy_resolver_factory.h", "//chrome/browser/profiles/profile.cc", @@ -72,6 +74,8 @@ source_set("qtwebengine_sources") { "//chrome/browser/ui/webui/quota_internals/quota_internals_ui.h", "//chrome/browser/ui/webui/task_scheduler_internals/task_scheduler_internals_ui.cc", "//chrome/browser/ui/webui/task_scheduler_internals/task_scheduler_internals_ui.h", + "//chrome/common/custom_handlers/protocol_handler.cc", + "//chrome/common/custom_handlers/protocol_handler.h", "//chrome/common/chrome_switches.cc", "//chrome/common/chrome_switches.h", "//chrome/common/pref_names.cc", @@ -80,12 +84,47 @@ source_set("qtwebengine_sources") { "//chrome/common/url_constants.h", "//chrome/common/webui_url_constants.cc", "//chrome/common/webui_url_constants.h", - "//extensions/common/constants.cc", - "//extensions/common/constants.h", - "//extensions/common/url_pattern.cc", - "//extensions/common/url_pattern.h", + "//components/prefs/in_memory_pref_store.cc", + "//components/prefs/in_memory_pref_store.h", ] + if (enable_extensions) { + deps += [ + ":qtwebengine_extensions_features", + "//chrome/browser/resources:component_extension_resources_grit", + "//chrome/common/extensions/api", + "//chrome/common/extensions/api:extensions_features", + "//components/crx_file", + "//components/crx_file:crx_creator", + "//components/spellcheck:buildflags", + "//extensions/buildflags:buildflags", + "//extensions/common", + "//extensions/common/api", + "//extensions/common:core_api_provider", + "//extensions/browser", + "//extensions/browser/api", + "//extensions/browser:core_api_provider", + "//extensions/renderer", + "//extensions:extensions_resources", + "//extensions/strings", + ] + sources += [ + "//chrome/common/extensions/permissions/chrome_api_permissions.cc", + "//chrome/common/extensions/permissions/chrome_api_permissions.h", + "//chrome/common/extensions/permissions/chrome_permission_message_provider.cc", + "//chrome/common/extensions/permissions/chrome_permission_message_provider.h", + "//chrome/common/extensions/permissions/chrome_permission_message_rules.cc", + "//chrome/common/extensions/permissions/chrome_permission_message_rules.h", + ] + } else { + sources += [ + "//extensions/common/constants.cc", + "//extensions/common/constants.h", + "//extensions/common/url_pattern.cc", + "//extensions/common/url_pattern.h", + ] + } + if (is_linux) { sources += [ "//chrome/browser/ui/webui/sandbox_internals_ui.cc", @@ -109,11 +148,6 @@ source_set("qtwebengine_sources") { "//chrome/renderer/pepper/pepper_shared_memory_message_filter.cc", "//chrome/renderer/pepper/pepper_shared_memory_message_filter.h", ] - - deps += [ - # Need to depend on //content/ppapi_plugin, which is private, thus depending on parent. - "//content", - ] } if (enable_basic_printing || enable_print_preview) { @@ -136,6 +170,8 @@ source_set("qtwebengine_sources") { deps += [ "//pdf", "//pdf:buildflags", + "//components/pdf/browser:browser", + "//components/pdf/renderer:renderer", "//components/printing/browser", "//components/printing/renderer", ] diff --git a/src/core/quota_permission_context_qt.cpp b/src/core/quota_permission_context_qt.cpp index cb1467364..a502e7fc8 100644 --- a/src/core/quota_permission_context_qt.cpp +++ b/src/core/quota_permission_context_qt.cpp @@ -39,7 +39,9 @@ #include "quota_permission_context_qt.h" +#include "base/task/post_task.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 "content/public/browser/render_frame_host.h" #include "quota_request_controller_impl.h" @@ -64,10 +66,10 @@ void QuotaPermissionContextQt::RequestQuotaPermission(const StorageQuotaParams & } if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) { - content::BrowserThread::PostTask( - content::BrowserThread::UI, FROM_HERE, - base::Bind(&QuotaPermissionContextQt::RequestQuotaPermission, this, - params, render_process_id, callback)); + base::PostTaskWithTraits( + FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(&QuotaPermissionContextQt::RequestQuotaPermission, this, + params, render_process_id, callback)); return; } @@ -95,10 +97,10 @@ void QuotaPermissionContextQt::dispatchCallbackOnIOThread(const PermissionCallba return; if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)) { - content::BrowserThread::PostTask( - content::BrowserThread::IO, FROM_HERE, - base::Bind(&QuotaPermissionContextQt::dispatchCallbackOnIOThread, - this, callback, response)); + base::PostTaskWithTraits( + FROM_HERE, {content::BrowserThread::IO}, + base::BindOnce(&QuotaPermissionContextQt::dispatchCallbackOnIOThread, + this, callback, response)); return; } diff --git a/src/core/render_view_context_menu_qt.h b/src/core/render_view_context_menu_qt.h index d8ca2775c..e1ee301fc 100644 --- a/src/core/render_view_context_menu_qt.h +++ b/src/core/render_view_context_menu_qt.h @@ -55,7 +55,7 @@ namespace QtWebEngineCore { -class QWEBENGINECORE_PRIVATE_EXPORT RenderViewContextMenuQt +class Q_WEBENGINECORE_PRIVATE_EXPORT RenderViewContextMenuQt { public: enum ContextMenuItem { diff --git a/src/core/render_widget_host_view_qt.cpp b/src/core/render_widget_host_view_qt.cpp index a5aba92bc..3be0c9390 100644 --- a/src/core/render_widget_host_view_qt.cpp +++ b/src/core/render_widget_host_view_qt.cpp @@ -40,19 +40,23 @@ #include "render_widget_host_view_qt.h" #include "browser_accessibility_manager_qt.h" -#include "chromium_overrides.h" #include "common/qt_messages.h" -#include "compositor.h" +#include "compositor/compositor.h" #include "qtwebenginecoreglobal_p.h" #include "render_widget_host_view_qt_delegate.h" +#include "touch_handle_drawable_client.h" +#include "touch_selection_controller_client_qt.h" +#include "touch_selection_menu_controller.h" #include "type_conversion.h" #include "web_contents_adapter_client.h" #include "web_event_factory.h" #include "components/viz/common/surfaces/frame_sink_id_allocator.h" -#include "content/browser/accessibility/browser_accessibility_state_impl.h" -#include "content/browser/frame_host/render_frame_host_impl.h" +#include "components/viz/host/host_frame_sink_manager.h" +#include "content/browser/compositor/surface_utils.h" #include "content/browser/frame_host/frame_tree.h" +#include "content/browser/frame_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" #include "content/common/content_switches_internal.h" #include "content/browser/renderer_host/render_widget_host_input_event_router.h" @@ -62,9 +66,11 @@ #include "third_party/blink/public/platform/web_cursor_info.h" #include "ui/events/blink/blink_event_util.h" #include "ui/events/event.h" +#include "ui/events/gesture_detection/gesture_configuration.h" #include "ui/events/gesture_detection/gesture_provider_config_helper.h" #include "ui/events/gesture_detection/motion_event.h" -#include "ui/gfx/geometry/size_conversions.h" +#include "ui/gfx/image/image_skia.h" +#include "ui/touch_selection/touch_selection_controller.h" #if defined(USE_OZONE) #include "ui/base/clipboard/scoped_clipboard_writer.h" @@ -83,7 +89,6 @@ #include <QFocusEvent> #include <QGuiApplication> #include <QInputMethodEvent> -#include <QLoggingCategory> #include <QTextFormat> #include <QKeyEvent> #include <QMouseEvent> @@ -94,7 +99,6 @@ #include <QWheelEvent> #include <QWindow> #include <QtGui/private/qinputcontrol_p.h> -#include <QtGui/qaccessible.h> namespace QtWebEngineCore { @@ -185,14 +189,13 @@ static inline bool isCommonTextEditShortcut(const QKeyEvent *ke) static uint32_t s_eventId = 0; class MotionEventQt : public ui::MotionEvent { public: - MotionEventQt(const QList<QTouchEvent::TouchPoint> &touchPoints, const base::TimeTicks &eventTime, Action action, const Qt::KeyboardModifiers modifiers, float dpiScale, int index = -1) + MotionEventQt(const QList<QTouchEvent::TouchPoint> &touchPoints, const base::TimeTicks &eventTime, Action action, const Qt::KeyboardModifiers modifiers, int index = -1) : touchPoints(touchPoints) , eventTime(eventTime) , action(action) , eventId(++s_eventId) , flags(flagsFromModifiers(modifiers)) , index(index) - , dpiScale(dpiScale) { // ACTION_DOWN and ACTION_UP must be accesssed through pointer_index 0 Q_ASSERT((action != Action::DOWN && action != Action::UP) || index == 0); @@ -203,8 +206,8 @@ public: int GetActionIndex() const override { return index; } size_t GetPointerCount() const override { return touchPoints.size(); } int GetPointerId(size_t pointer_index) const override { return touchPoints.at(pointer_index).id(); } - float GetX(size_t pointer_index) const override { return touchPoints.at(pointer_index).pos().x() / dpiScale; } - float GetY(size_t pointer_index) const override { return touchPoints.at(pointer_index).pos().y() / dpiScale; } + float GetX(size_t pointer_index) const override { return touchPoints.at(pointer_index).pos().x(); } + float GetY(size_t pointer_index) const override { return touchPoints.at(pointer_index).pos().y(); } float GetRawX(size_t pointer_index) const override { return touchPoints.at(pointer_index).screenPos().x(); } float GetRawY(size_t pointer_index) const override { return touchPoints.at(pointer_index).screenPos().y(); } float GetTouchMajor(size_t pointer_index) const override @@ -225,6 +228,8 @@ public: float GetPressure(size_t pointer_index) const override { return touchPoints.at(pointer_index).pressure(); } float GetTiltX(size_t pointer_index) const override { return 0; } float GetTiltY(size_t pointer_index) const override { return 0; } + float GetTwist(size_t) const override { return 0; } + float GetTangentialPressure(size_t) const override { return 0; } base::TimeTicks GetEventTime() const override { return eventTime; } size_t GetHistorySize() const override { return 0; } @@ -232,7 +237,10 @@ public: float GetHistoricalTouchMajor(size_t pointer_index, size_t historical_index) const override { return 0; } float GetHistoricalX(size_t pointer_index, size_t historical_index) const override { return 0; } float GetHistoricalY(size_t pointer_index, size_t historical_index) const override { return 0; } - ToolType GetToolType(size_t pointer_index) const override { return ui::MotionEvent::ToolType::FINGER; } + ToolType GetToolType(size_t pointer_index) const override { + return (touchPoints.at(pointer_index).flags() & QTouchEvent::TouchPoint::InfoFlag::Pen) ? ui::MotionEvent::ToolType::STYLUS + : ui::MotionEvent::ToolType::FINGER; + } int GetButtonState() const override { return 0; } private: @@ -242,20 +250,22 @@ private: const uint32_t eventId; int flags; int index; - float dpiScale; }; -bool isAccessibilityEnabled() { - // On Linux accessibility is disabled by default due to performance issues, - // and can be re-enabled by setting the QTWEBENGINE_ENABLE_LINUX_ACCESSIBILITY environment - // variable. For details, see QTBUG-59922. -#ifdef Q_OS_LINUX - static bool accessibility_enabled - = qEnvironmentVariableIsSet("QTWEBENGINE_ENABLE_LINUX_ACCESSIBILITY"); -#else - const bool accessibility_enabled = true; -#endif - return accessibility_enabled; +static content::ScreenInfo screenInfoFromQScreen(QScreen *screen) +{ + content::ScreenInfo r; + if (screen) { + r.device_scale_factor = screen->devicePixelRatio(); + r.depth_per_component = 8; + r.depth = screen->depth(); + r.is_monochrome = (r.depth == 1); + r.rect = toGfx(screen->geometry()); + r.available_rect = toGfx(screen->availableGeometry()); + } else { + r.device_scale_factor = qGuiApp->devicePixelRatio(); + } + return r; } RenderWidgetHostViewQt::RenderWidgetHostViewQt(content::RenderWidgetHost *widget) @@ -263,7 +273,7 @@ RenderWidgetHostViewQt::RenderWidgetHostViewQt(content::RenderWidgetHost *widget , m_gestureProvider(QtGestureProviderConfig(), this) , m_sendMotionActionDown(false) , m_touchMotionStarted(false) - , m_compositor(new Compositor(this)) + , m_compositor(new Compositor(widget)) , m_loadVisuallyCommittedState(NotCommitted) , m_adapterClient(0) , m_imeInProgress(false) @@ -274,20 +284,10 @@ RenderWidgetHostViewQt::RenderWidgetHostViewQt(content::RenderWidgetHost *widget , m_cursorPosition(0) , m_emptyPreviousSelection(true) , m_wheelAckPending(false) - , m_pendingResize(false) , m_mouseWheelPhaseHandler(this) - // This frame-sink id is based on what RenderWidgetHostViewChildFrame does: - , m_frameSinkId(base::checked_cast<uint32_t>(widget->GetProcess()->GetID()), - base::checked_cast<uint32_t>(widget->GetRoutingID())) + , m_frameSinkId(host()->GetFrameSinkId()) { host()->SetView(this); -#ifndef QT_NO_ACCESSIBILITY - if (isAccessibilityEnabled()) { - QAccessible::installActivationObserver(this); - if (QAccessible::isActive()) - content::BrowserAccessibilityStateImpl::GetInstance()->EnableAccessibility(); - } -#endif // QT_NO_ACCESSIBILITY if (GetTextInputManager()) GetTextInputManager()->AddObserver(this); @@ -295,27 +295,32 @@ RenderWidgetHostViewQt::RenderWidgetHostViewQt(content::RenderWidgetHost *widget const QPlatformInputContext *context = QGuiApplicationPrivate::platformIntegration()->inputContext(); m_imeHasHiddenTextCapability = context && context->hasCapability(QPlatformInputContext::HiddenTextCapability); - m_localSurfaceId = m_localSurfaceIdAllocator.GenerateId(); - if (host()->delegate() && host()->delegate()->GetInputEventRouter()) host()->delegate()->GetInputEventRouter()->AddFrameSinkIdOwner(GetFrameSinkId(), this); + + m_touchSelectionControllerClient.reset(new TouchSelectionControllerClientQt(this)); + ui::TouchSelectionController::Config config; + config.max_tap_duration = base::TimeDelta::FromMilliseconds(ui::GestureConfiguration::GetInstance()->long_press_time_in_ms()); + config.tap_slop = ui::GestureConfiguration::GetInstance()->max_touch_move_in_pixels_for_click(); + config.enable_longpress_drag_selection = false; + m_touchSelectionController.reset(new ui::TouchSelectionController(m_touchSelectionControllerClient.get(), config)); } RenderWidgetHostViewQt::~RenderWidgetHostViewQt() { QObject::disconnect(m_adapterClientDestroyedConnection); -#ifndef QT_NO_ACCESSIBILITY - QAccessible::removeActivationObserver(this); -#endif // QT_NO_ACCESSIBILITY if (text_input_manager_) text_input_manager_->RemoveObserver(this); + + m_touchSelectionController.reset(); + m_touchSelectionControllerClient.reset(); } void RenderWidgetHostViewQt::setDelegate(RenderWidgetHostViewQtDelegate* delegate) { m_delegate.reset(delegate); - m_compositor->setViewDelegate(delegate); + visualPropertiesChanged(); } void RenderWidgetHostViewQt::setAdapterClient(WebContentsAdapterClient *adapterClient) @@ -342,30 +347,16 @@ void RenderWidgetHostViewQt::InitAsFullscreen(content::RenderWidgetHostView*) { } -void RenderWidgetHostViewQt::SetSize(const gfx::Size& size) +void RenderWidgetHostViewQt::SetSize(const gfx::Size &sizeInDips) { - int width = size.width(); - int height = size.height(); - - m_delegate->resize(width,height); + m_delegate->resize(sizeInDips.width(), sizeInDips.height()); } -void RenderWidgetHostViewQt::SetBounds(const gfx::Rect& screenRect) +void RenderWidgetHostViewQt::SetBounds(const gfx::Rect &windowRectInDips) { - // This is called when webkit has sent us a Move message. - if (IsPopup()) - m_delegate->move(toQt(screenRect.origin())); - SetSize(screenRect.size()); -} - -gfx::Size RenderWidgetHostViewQt::GetCompositorViewportPixelSize() const -{ - if (!m_delegate || !m_delegate->window() || !m_delegate->window()->screen()) - return gfx::Size(); - - const QScreen* screen = m_delegate->window()->screen(); - gfx::SizeF size = toGfx(m_delegate->screenRect().size()); - return gfx::ToCeiledSize(gfx::ScaleSize(size, screen->devicePixelRatio())); + DCHECK(IsPopup()); + m_delegate->move(toQt(windowRectInDips.origin())); + m_delegate->resize(windowRectInDips.width(), windowRectInDips.height()); } gfx::NativeView RenderWidgetHostViewQt::GetNativeView() const @@ -444,11 +435,7 @@ bool RenderWidgetHostViewQt::IsShowing() // Retrieve the bounds of the View, in screen coordinates. gfx::Rect RenderWidgetHostViewQt::GetViewBounds() const { - QRectF p = m_delegate->contentsRect(); - float s = dpiScale(); - gfx::Point p1(floor(p.x() / s), floor(p.y() / s)); - gfx::Point p2(ceil(p.right() /s), ceil(p.bottom() / s)); - return gfx::BoundingRect(p1, p2); + return m_viewRectInDips; } void RenderWidgetHostViewQt::UpdateBackgroundColor() @@ -603,15 +590,13 @@ void RenderWidgetHostViewQt::DisplayCursor(const content::WebCursor &webCursor) } #if defined(USE_AURA) if (auraType != ui::CursorType::kNull) { - QWindow *window = m_delegate->window(); - qreal windowDpr = window ? window->devicePixelRatio() : 1.0f; int resourceId; gfx::Point hotspot; // GetCursorDataFor only knows hotspots for 1x and 2x cursor images, in physical pixels. - qreal hotspotDpr = windowDpr <= 1.0f ? 1.0f : 2.0f; + qreal hotspotDpr = m_screenInfo.device_scale_factor <= 1.0f ? 1.0f : 2.0f; if (ui::GetCursorDataFor(ui::CursorSize::kNormal, auraType, hotspotDpr, &resourceId, &hotspot)) { if (const gfx::ImageSkia *imageSkia = ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(resourceId)) { - QImage imageQt = toQImage(imageSkia->GetRepresentation(windowDpr)); + QImage imageQt = toQImage(imageSkia->GetRepresentation(m_screenInfo.device_scale_factor)); // Convert hotspot coordinates into device-independent pixels. qreal hotX = hotspot.x() / hotspotDpr; @@ -693,12 +678,9 @@ void RenderWidgetHostViewQt::SubmitCompositorFrame(const viz::LocalSurfaceId &lo if (frame_token) OnFrameTokenChangedForView(frame_token); - // Support experimental.viewport.devicePixelRatio, see GetScreenInfo implementation below. - float dpiScale = this->dpiScale(); - if (dpiScale != 0 && dpiScale != 1) - frame.metadata.device_scale_factor /= dpiScale; - - m_compositor->submitFrame(std::move(frame)); + m_compositor->submitFrame( + std::move(frame), + base::BindOnce(&RenderWidgetHostViewQtDelegate::update, base::Unretained(m_delegate.get()))); if (m_loadVisuallyCommittedState == NotCommitted) { m_loadVisuallyCommittedState = DidFirstCompositorFrameSwap; @@ -711,31 +693,16 @@ void RenderWidgetHostViewQt::SubmitCompositorFrame(const viz::LocalSurfaceId &lo m_adapterClient->updateScrollPosition(toQt(m_lastScrollOffset)); if (contentsSizeChanged) m_adapterClient->updateContentsSize(toQt(m_lastContentsSize)); - - if (m_pendingResize && host()) { - if (host()->SynchronizeVisualProperties()) - m_pendingResize = false; - } } void RenderWidgetHostViewQt::GetScreenInfo(content::ScreenInfo *results) const { - QWindow *window = m_delegate->window(); - if (!window) - return; - GetScreenInfoFromNativeWindow(window, results); - - // Support experimental.viewport.devicePixelRatio - results->device_scale_factor *= dpiScale(); + *results = m_screenInfo; } gfx::Rect RenderWidgetHostViewQt::GetBoundsInRootWindow() { - if (!m_delegate->window()) - return gfx::Rect(); - - QRect r = m_delegate->window()->frameGeometry(); - return gfx::Rect(r.x(), r.y(), r.width(), r.height()); + return m_windowRectInDips; } void RenderWidgetHostViewQt::ClearCompositorFrame() @@ -756,9 +723,12 @@ void RenderWidgetHostViewQt::OnUpdateTextInputStateCalled(content::TextInputMana } ui::TextInputType type = getTextInputType(); +#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) m_delegate->setInputMethodHints(toQtInputMethodHints(getTextInputType()) | Qt::ImhNoPredictiveText | Qt::ImhNoTextHandles | Qt::ImhNoEditMenu); - - m_surroundingText = QString::fromStdString(state->value); +#else + m_delegate->setInputMethodHints(toQtInputMethodHints(getTextInputType()) | Qt::ImhNoPredictiveText); +#endif + m_surroundingText = toQt(state->value); // Remove IME composition text from the surrounding text if (state->composition_start != -1 && state->composition_end != -1) m_surroundingText.remove(state->composition_start, state->composition_end - state->composition_start); @@ -904,7 +874,33 @@ void RenderWidgetHostViewQt::OnGestureEvent(const ui::GestureEventData& gesture) return; } - host()->ForwardGestureEvent(ui::CreateWebGestureEventFromGestureEventData(gesture)); + blink::WebGestureEvent event = ui::CreateWebGestureEventFromGestureEventData(gesture); + + if (m_touchSelectionController && m_touchSelectionControllerClient) { + switch (event.GetType()) { + case blink::WebInputEvent::kGestureLongPress: + m_touchSelectionController->HandleLongPressEvent(event.TimeStamp(), event.PositionInWidget()); + break; + case blink::WebInputEvent::kGestureTap: + m_touchSelectionController->HandleTapEvent(event.PositionInWidget(), event.data.tap.tap_count); + break; + case blink::WebInputEvent::kGestureScrollBegin: + m_touchSelectionControllerClient->onScrollBegin(); + break; + case blink::WebInputEvent::kGestureScrollEnd: + m_touchSelectionControllerClient->onScrollEnd(); + break; + default: + break; + } + } + + host()->ForwardGestureEvent(event); +} + +void RenderWidgetHostViewQt::DidStopFlinging() +{ + m_touchSelectionControllerClient->DidStopFlinging(); } viz::ScopedSurfaceIdAllocator RenderWidgetHostViewQt::DidUpdateVisualProperties(const cc::RenderFrameMetadata &metadata) @@ -917,27 +913,12 @@ viz::ScopedSurfaceIdAllocator RenderWidgetHostViewQt::DidUpdateVisualProperties( void RenderWidgetHostViewQt::OnDidUpdateVisualPropertiesComplete(const cc::RenderFrameMetadata &metadata) { - if (metadata.local_surface_id) - m_localSurfaceIdAllocator.UpdateFromChild(*metadata.local_surface_id); - - m_localSurfaceId = m_localSurfaceIdAllocator.GenerateId(); - host()->SendScreenRects(); - if (m_pendingResize) { - if (host()->SynchronizeVisualProperties()) - m_pendingResize = false; - } + synchronizeVisualProperties(metadata.local_surface_id_allocation); } QSGNode *RenderWidgetHostViewQt::updatePaintNode(QSGNode *oldNode) { - return m_compositor->updatePaintNode(oldNode); -} - -void RenderWidgetHostViewQt::notifyResize() -{ - m_pendingResize = true; - if (host()->SynchronizeVisualProperties()) - m_pendingResize = false; + return m_compositor->updatePaintNode(oldNode, m_delegate.get()); } void RenderWidgetHostViewQt::notifyShown() @@ -950,17 +931,26 @@ void RenderWidgetHostViewQt::notifyHidden() host()->WasHidden(); } -void RenderWidgetHostViewQt::windowBoundsChanged() +void RenderWidgetHostViewQt::visualPropertiesChanged() { - host()->SendScreenRects(); - if (m_delegate && m_delegate->window()) - host()->NotifyScreenInfoChanged(); -} + if (!m_delegate) + return; -void RenderWidgetHostViewQt::windowChanged() -{ - if (m_delegate && m_delegate->window()) - host()->NotifyScreenInfoChanged(); + gfx::Rect oldViewRect = m_viewRectInDips; + m_viewRectInDips = toGfx(m_delegate->viewGeometry().toAlignedRect()); + + gfx::Rect oldWindowRect = m_windowRectInDips; + m_windowRectInDips = toGfx(m_delegate->windowGeometry()); + + QWindow *window = m_delegate->window(); + content::ScreenInfo oldScreenInfo = m_screenInfo; + m_screenInfo = screenInfoFromQScreen(window ? window->screen() : nullptr); + + if (m_viewRectInDips != oldViewRect || m_windowRectInDips != oldWindowRect) + host()->SendScreenRects(); + + if (m_viewRectInDips.size() != oldViewRect.size() || m_screenInfo != oldScreenInfo) + synchronizeVisualProperties(base::nullopt); } bool RenderWidgetHostViewQt::forwardEvent(QEvent *event) @@ -1114,7 +1104,11 @@ QVariant RenderWidgetHostViewQt::inputMethodQuery(Qt::InputMethodQuery query) // TODO: Implement this return QVariant(); // No limit. case Qt::ImHints: +#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) return int(toQtInputMethodHints(getTextInputType()) | Qt::ImhNoPredictiveText | Qt::ImhNoTextHandles | Qt::ImhNoEditMenu); +#else + return int(toQtInputMethodHints(getTextInputType()) | Qt::ImhNoPredictiveText); +#endif default: return QVariant(); } @@ -1166,14 +1160,9 @@ QList<QTouchEvent::TouchPoint> RenderWidgetHostViewQt::mapTouchPointIds(const QL return outputPoints; } -float RenderWidgetHostViewQt::dpiScale() const -{ - return m_adapterClient ? m_adapterClient->dpiScale() : 1.0; -} - bool RenderWidgetHostViewQt::IsPopup() const { - return popup_type_ != blink::kWebPopupTypeNone; + return widget_type_ == content::WidgetType::kPopup; } void RenderWidgetHostViewQt::handleMouseEvent(QMouseEvent* event) @@ -1315,9 +1304,9 @@ void RenderWidgetHostViewQt::handleInputMethodEvent(QInputMethodEvent *ev) } if (hasSelection) { - content::RenderFrameHostImpl *frameHost = static_cast<content::RenderFrameHostImpl *>(getFocusedFrameHost()); - if (frameHost) - frameHost->GetFrameInputHandler()->SetEditableSelectionOffsets(selectionRange.start(), selectionRange.end()); + content::mojom::FrameInputHandler *frameInputHandler = getFrameInputHandler(); + if (frameInputHandler) + frameInputHandler->SetEditableSelectionOffsets(selectionRange.start(), selectionRange.end()); } int replacementLength = ev->replacementLength(); @@ -1394,21 +1383,11 @@ void RenderWidgetHostViewQt::handleInputMethodQueryEvent(QInputMethodQueryEvent ev->accept(); } -#ifndef QT_NO_ACCESSIBILITY -void RenderWidgetHostViewQt::accessibilityActiveChanged(bool active) -{ - if (active) - content::BrowserAccessibilityStateImpl::GetInstance()->EnableAccessibility(); - else - content::BrowserAccessibilityStateImpl::GetInstance()->DisableAccessibility(); -} -#endif // QT_NO_ACCESSIBILITY - void RenderWidgetHostViewQt::handleWheelEvent(QWheelEvent *ev) { if (!m_wheelAckPending) { Q_ASSERT(m_pendingWheelEvents.isEmpty()); - blink::WebMouseWheelEvent webEvent = WebEventFactory::toWebWheelEvent(ev, dpiScale()); + blink::WebMouseWheelEvent webEvent = WebEventFactory::toWebWheelEvent(ev); m_wheelAckPending = (webEvent.phase != blink::WebMouseWheelEvent::kPhaseEnded); m_mouseWheelPhaseHandler.AddPhaseIfNeededAndScheduleEndEvent(webEvent, false); host()->ForwardWheelEvent(webEvent); @@ -1416,10 +1395,10 @@ void RenderWidgetHostViewQt::handleWheelEvent(QWheelEvent *ev) } if (!m_pendingWheelEvents.isEmpty()) { // Try to combine with this wheel event with the last pending one. - if (WebEventFactory::coalesceWebWheelEvent(m_pendingWheelEvents.last(), ev, dpiScale())) + if (WebEventFactory::coalesceWebWheelEvent(m_pendingWheelEvents.last(), ev)) return; } - m_pendingWheelEvents.append(WebEventFactory::toWebWheelEvent(ev, dpiScale())); + m_pendingWheelEvents.append(WebEventFactory::toWebWheelEvent(ev)); } void RenderWidgetHostViewQt::WheelEventAck(const blink::WebMouseWheelEvent &event, content::InputEventAckState /*ack_result*/) @@ -1454,16 +1433,11 @@ void RenderWidgetHostViewQt::handleGestureEvent(QNativeGestureEvent *ev) const Qt::NativeGestureType type = ev->gestureType(); // These are the only supported gestures by Chromium so far. if (type == Qt::ZoomNativeGesture || type == Qt::SmartZoomNativeGesture) { - host()->ForwardGestureEvent(WebEventFactory::toWebGestureEvent( - ev, - static_cast<double>(dpiScale()))); + host()->ForwardGestureEvent(WebEventFactory::toWebGestureEvent(ev)); } } #endif -Q_DECLARE_LOGGING_CATEGORY(QWEBENGINE_TOUCH_HANDLING); -Q_LOGGING_CATEGORY(QWEBENGINE_TOUCH_HANDLING, "qt.webengine.touch"); - void RenderWidgetHostViewQt::handleTouchEvent(QTouchEvent *ev) { // On macOS instead of handling touch events, we use the OS provided QNativeGestureEvents. @@ -1471,7 +1445,7 @@ void RenderWidgetHostViewQt::handleTouchEvent(QTouchEvent *ev) if (ev->spontaneous()) { return; } else { - qCWarning(QWEBENGINE_TOUCH_HANDLING) + VLOG(1) << "Sending simulated touch events to Chromium does not work properly on macOS. " "Consider using QNativeGestureEvents or QMouseEvents."; } @@ -1488,11 +1462,35 @@ void RenderWidgetHostViewQt::handleTouchEvent(QTouchEvent *ev) eventTimestamp += m_eventsToNowDelta; QList<QTouchEvent::TouchPoint> touchPoints = mapTouchPointIds(ev->touchPoints()); + { + ui::MotionEvent::Action action; + switch (touchPoints[0].state()) { + case Qt::TouchPointPressed: + action = ui::MotionEvent::Action::DOWN; + break; + case Qt::TouchPointMoved: + action = ui::MotionEvent::Action::MOVE; + break; + case Qt::TouchPointReleased: + action = ui::MotionEvent::Action::UP; + break; + default: + action = ui::MotionEvent::Action::NONE; + break; + } + + MotionEventQt motionEvent(touchPoints, eventTimestamp, action, ev->modifiers(), 0); + if (m_touchSelectionController->WillHandleTouchEvent(motionEvent)) { + ev->accept(); + return; + } + } switch (ev->type()) { case QEvent::TouchBegin: m_sendMotionActionDown = true; m_touchMotionStarted = true; + m_touchSelectionControllerClient->onTouchDown(); break; case QEvent::TouchUpdate: m_touchMotionStarted = true; @@ -1512,13 +1510,13 @@ void RenderWidgetHostViewQt::handleTouchEvent(QTouchEvent *ev) if (touchPoints.isEmpty()) touchPoints = m_previousTouchPoints; clearPreviousTouchMotionState(); - MotionEventQt cancelEvent(touchPoints, eventTimestamp, ui::MotionEvent::Action::CANCEL, - ev->modifiers(), dpiScale()); + MotionEventQt cancelEvent(touchPoints, eventTimestamp, ui::MotionEvent::Action::CANCEL, ev->modifiers()); processMotionEvent(cancelEvent); return; } case QEvent::TouchEnd: clearPreviousTouchMotionState(); + m_touchSelectionControllerClient->onTouchUp(); break; default: break; @@ -1565,8 +1563,7 @@ void RenderWidgetHostViewQt::handleTouchEvent(QTouchEvent *ev) continue; } - MotionEventQt motionEvent(touchPoints, eventTimestamp, action, ev->modifiers(), dpiScale(), - i); + MotionEventQt motionEvent(touchPoints, eventTimestamp, action, ev->modifiers(), i); processMotionEvent(motionEvent); } } @@ -1583,7 +1580,7 @@ void RenderWidgetHostViewQt::handlePointerEvent(T *event) { // Currently WebMouseEvent is a subclass of WebPointerProperties, so basically // tablet events are mouse events with extra properties. - blink::WebMouseEvent webEvent = WebEventFactory::toWebMouseEvent(event, dpiScale()); + blink::WebMouseEvent webEvent = WebEventFactory::toWebMouseEvent(event); if ((webEvent.GetType() == blink::WebInputEvent::kMouseDown || webEvent.GetType() == blink::WebInputEvent::kMouseUp) && webEvent.button == blink::WebMouseEvent::Button::kNoButton) { // Blink can only handle the 3 main mouse-buttons and may assert when processing mouse-down for no button. @@ -1629,7 +1626,7 @@ void RenderWidgetHostViewQt::handlePointerEvent(T *event) void RenderWidgetHostViewQt::handleHoverEvent(QHoverEvent *ev) { - host()->ForwardMouseEvent(WebEventFactory::toWebMouseEvent(ev, dpiScale())); + host()->ForwardMouseEvent(WebEventFactory::toWebMouseEvent(ev)); } void RenderWidgetHostViewQt::handleFocusEvent(QFocusEvent *ev) @@ -1656,11 +1653,6 @@ void RenderWidgetHostViewQt::SetNeedsBeginFrames(bool needs_begin_frames) m_compositor->setNeedsBeginFrames(needs_begin_frames); } -void RenderWidgetHostViewQt::OnBeginFrame(base::TimeTicks frame_time) -{ - host()->ProgressFlingIfNeeded(frame_time); -} - content::RenderFrameHost *RenderWidgetHostViewQt::getFocusedFrameHost() { content::RenderViewHostImpl *viewHost = content::RenderViewHostImpl::From(host()); @@ -1674,6 +1666,15 @@ content::RenderFrameHost *RenderWidgetHostViewQt::getFocusedFrameHost() return focusedFrame->current_frame_host(); } +content::mojom::FrameInputHandler *RenderWidgetHostViewQt::getFrameInputHandler() +{ + content::RenderFrameHostImpl *frameHost = static_cast<content::RenderFrameHostImpl *>(getFocusedFrameHost()); + if (!frameHost) + return nullptr; + + return frameHost->GetFrameInputHandler(); +} + ui::TextInputType RenderWidgetHostViewQt::getTextInputType() const { if (text_input_manager_ && text_input_manager_->GetTextInputState()) @@ -1696,9 +1697,9 @@ const viz::FrameSinkId &RenderWidgetHostViewQt::GetFrameSinkId() const return m_frameSinkId; } -const viz::LocalSurfaceId &RenderWidgetHostViewQt::GetLocalSurfaceId() const +const viz::LocalSurfaceIdAllocation &RenderWidgetHostViewQt::GetLocalSurfaceIdAllocation() const { - return m_localSurfaceId; + return m_localSurfaceIdAllocator.GetCurrentLocalSurfaceIdAllocation(); } void RenderWidgetHostViewQt::TakeFallbackContentFrom(content::RenderWidgetHostView *view) @@ -1710,16 +1711,40 @@ void RenderWidgetHostViewQt::TakeFallbackContentFrom(content::RenderWidgetHostVi SetBackgroundColor(*color); } -void RenderWidgetHostViewQt::EnsureSurfaceSynchronizedForLayoutTest() +void RenderWidgetHostViewQt::EnsureSurfaceSynchronizedForWebTest() { - ++m_latestCaptureSequenceNumber; - if (host()) - host()->SynchronizeVisualProperties(); + NOTIMPLEMENTED(); } uint32_t RenderWidgetHostViewQt::GetCaptureSequenceNumber() const { - return m_latestCaptureSequenceNumber; + return 0; +} + +void RenderWidgetHostViewQt::ResetFallbackToFirstNavigationSurface() +{ +} + +void RenderWidgetHostViewQt::OnRenderFrameMetadataChangedAfterActivation() +{ + content::RenderWidgetHostViewBase::OnRenderFrameMetadataChangedAfterActivation(); + + const cc::RenderFrameMetadata &metadata = host()->render_frame_metadata_provider()->LastRenderFrameMetadata(); + if (metadata.selection.start != m_selectionStart || metadata.selection.end != m_selectionEnd) { + m_selectionStart = metadata.selection.start; + m_selectionEnd = metadata.selection.end; + m_touchSelectionControllerClient->UpdateClientSelectionBounds(m_selectionStart, m_selectionEnd); + } +} + +void RenderWidgetHostViewQt::synchronizeVisualProperties(const base::Optional<viz::LocalSurfaceIdAllocation> &childSurfaceId) +{ + if (childSurfaceId) + m_localSurfaceIdAllocator.UpdateFromChild(*childSurfaceId); + else + m_localSurfaceIdAllocator.GenerateId(); + + host()->SynchronizeVisualProperties(); } } // namespace QtWebEngineCore diff --git a/src/core/render_widget_host_view_qt.h b/src/core/render_widget_host_view_qt.h index a12ffe636..6e9ddabb9 100644 --- a/src/core/render_widget_host_view_qt.h +++ b/src/core/render_widget_host_view_qt.h @@ -46,18 +46,17 @@ #include "components/viz/common/frame_sinks/begin_frame_source.h" #include "components/viz/common/resources/transferable_resource.h" #include "components/viz/common/surfaces/parent_local_surface_id_allocator.h" +#include "components/viz/host/host_frame_sink_client.h" #include "content/browser/accessibility/browser_accessibility_manager.h" #include "content/browser/renderer_host/input/mouse_wheel_phase_handler.h" #include "content/browser/renderer_host/render_widget_host_view_base.h" #include "content/browser/renderer_host/text_input_manager.h" -#include "content/common/view_messages.h" #include "gpu/ipc/common/gpu_messages.h" #include "ui/events/gesture_detection/filtered_gesture_provider.h" #include "qtwebenginecoreglobal_p.h" #include <QMap> #include <QPoint> #include <QtGlobal> -#include <QtGui/qaccessible.h> #include <QtGui/QTouchEvent> QT_BEGIN_NAMESPACE @@ -67,11 +66,21 @@ QT_END_NAMESPACE namespace content { class RenderFrameHost; class RenderWidgetHostImpl; +namespace mojom { +class FrameInputHandler; +} +} + +namespace ui { +class TouchSelectionController; } namespace QtWebEngineCore { class Compositor; +class TouchHandleDrawableClient; +class TouchSelectionControllerClientQt; +class TouchSelectionMenuController; struct MultipleMouseClickHelper { @@ -94,9 +103,6 @@ class RenderWidgetHostViewQt , public ui::GestureProviderClient , public RenderWidgetHostViewQtDelegateClient , public base::SupportsWeakPtr<RenderWidgetHostViewQt> -#ifndef QT_NO_ACCESSIBILITY - , public QAccessible::ActivationObserver -#endif // QT_NO_ACCESSIBILITY , public content::TextInputManager::Observer { public: @@ -111,15 +117,14 @@ public: RenderWidgetHostViewQtDelegate *delegate() { return m_delegate.get(); } void setDelegate(RenderWidgetHostViewQtDelegate *delegate); + WebContentsAdapterClient *adapterClient() { return m_adapterClient; } void setAdapterClient(WebContentsAdapterClient *adapterClient); - void OnBeginFrame(base::TimeTicks frame_time); void InitAsChild(gfx::NativeView) override; void InitAsPopup(content::RenderWidgetHostView*, const gfx::Rect&) override; void InitAsFullscreen(content::RenderWidgetHostView*) override; void SetSize(const gfx::Size& size) override; void SetBounds(const gfx::Rect&) override; - gfx::Size GetCompositorViewportPixelSize() const override; gfx::NativeView GetNativeView() const override; gfx::NativeViewAccessible GetNativeViewAccessible() override; void Focus() override; @@ -159,21 +164,21 @@ public: void SetWantsAnimateOnlyBeginFrames() override; viz::SurfaceId GetCurrentSurfaceId() const override; const viz::FrameSinkId &GetFrameSinkId() const override; - const viz::LocalSurfaceId &GetLocalSurfaceId() const override; + const viz::LocalSurfaceIdAllocation &GetLocalSurfaceIdAllocation() const override; void TakeFallbackContentFrom(content::RenderWidgetHostView *view) override; - void EnsureSurfaceSynchronizedForLayoutTest() override; + void EnsureSurfaceSynchronizedForWebTest() override; uint32_t GetCaptureSequenceNumber() const override; + void ResetFallbackToFirstNavigationSurface() override; + void DidStopFlinging() override; // Overridden from ui::GestureProviderClient. void OnGestureEvent(const ui::GestureEventData& gesture) override; // Overridden from RenderWidgetHostViewQtDelegateClient. QSGNode *updatePaintNode(QSGNode *) override; - void notifyResize() override; void notifyShown() override; void notifyHidden() override; - void windowBoundsChanged() override; - void windowChanged() override; + void visualPropertiesChanged() override; bool forwardEvent(QEvent *) override; QVariant inputMethodQuery(Qt::InputMethodQuery query) override; void closePopup() override; @@ -209,27 +214,37 @@ public: // Overridden from content::BrowserAccessibilityDelegate content::BrowserAccessibilityManager* CreateBrowserAccessibilityManager(content::BrowserAccessibilityDelegate* delegate, bool for_root_frame) override; -#ifndef QT_NO_ACCESSIBILITY - void accessibilityActiveChanged(bool active) override; -#endif // QT_NO_ACCESSIBILITY LoadVisuallyCommittedState getLoadVisuallyCommittedState() const { return m_loadVisuallyCommittedState; } void setLoadVisuallyCommittedState(LoadVisuallyCommittedState state) { m_loadVisuallyCommittedState = state; } + // Overridden from content::RenderFrameMetadataProvider::Observer + void OnRenderFrameMetadataChangedAfterActivation() override; + gfx::SizeF lastContentsSize() const { return m_lastContentsSize; } gfx::Vector2dF lastScrollOffset() const { return m_lastScrollOffset; } + ui::TouchSelectionController *getTouchSelectionController() const { return m_touchSelectionController.get(); } + TouchSelectionControllerClientQt *getTouchSelectionControllerClient() const { return m_touchSelectionControllerClient.get(); } + content::mojom::FrameInputHandler *getFrameInputHandler(); + ui::TextInputType getTextInputType() const; + private: void processMotionEvent(const ui::MotionEvent &motionEvent); void clearPreviousTouchMotionState(); QList<QTouchEvent::TouchPoint> mapTouchPointIds(const QList<QTouchEvent::TouchPoint> &inputPoints); - float dpiScale() const; - void updateNeedsBeginFramesInternal(); bool IsPopup() const; void selectionChanged(); content::RenderFrameHost *getFocusedFrameHost(); - ui::TextInputType getTextInputType() const; + + void synchronizeVisualProperties(const base::Optional<viz::LocalSurfaceIdAllocation> &childSurfaceId); + + // Geometry of the view in screen DIPs. + gfx::Rect m_viewRectInDips; + // Geometry of the window, including frame, in screen DIPs. + gfx::Rect m_windowRectInDips; + content::ScreenInfo m_screenInfo; ui::FilteredGestureProvider m_gestureProvider; base::TimeDelta m_eventsToNowDelta; @@ -252,7 +267,6 @@ private: gfx::Vector2dF m_lastScrollOffset; gfx::SizeF m_lastContentsSize; - viz::LocalSurfaceId m_localSurfaceId; viz::ParentLocalSurfaceIdAllocator m_localSurfaceIdAllocator; uint m_imState; @@ -265,13 +279,16 @@ private: bool m_imeHasHiddenTextCapability; bool m_wheelAckPending; - bool m_pendingResize; QList<blink::WebMouseWheelEvent> m_pendingWheelEvents; content::MouseWheelPhaseHandler m_mouseWheelPhaseHandler; viz::FrameSinkId m_frameSinkId; - uint32_t m_latestCaptureSequenceNumber = 0u; std::string m_editCommand; + + std::unique_ptr<TouchSelectionControllerClientQt> m_touchSelectionControllerClient; + std::unique_ptr<ui::TouchSelectionController> m_touchSelectionController; + gfx::SelectionBound m_selectionStart; + gfx::SelectionBound m_selectionEnd; }; } // namespace QtWebEngineCore diff --git a/src/core/render_widget_host_view_qt_delegate.h b/src/core/render_widget_host_view_qt_delegate.h index 5ce595502..6066284d9 100644 --- a/src/core/render_widget_host_view_qt_delegate.h +++ b/src/core/render_widget_host_view_qt_delegate.h @@ -74,26 +74,24 @@ namespace QtWebEngineCore { class WebContentsAdapterClient; -class QWEBENGINECORE_PRIVATE_EXPORT RenderWidgetHostViewQtDelegateClient { +class Q_WEBENGINECORE_PRIVATE_EXPORT RenderWidgetHostViewQtDelegateClient { public: virtual ~RenderWidgetHostViewQtDelegateClient() { } virtual QSGNode *updatePaintNode(QSGNode *) = 0; - virtual void notifyResize() = 0; virtual void notifyShown() = 0; virtual void notifyHidden() = 0; - virtual void windowBoundsChanged() = 0; - virtual void windowChanged() = 0; + virtual void visualPropertiesChanged() = 0; virtual bool forwardEvent(QEvent *) = 0; virtual QVariant inputMethodQuery(Qt::InputMethodQuery query) = 0; virtual void closePopup() = 0; }; -class QWEBENGINECORE_PRIVATE_EXPORT RenderWidgetHostViewQtDelegate { +class Q_WEBENGINECORE_PRIVATE_EXPORT RenderWidgetHostViewQtDelegate { public: virtual ~RenderWidgetHostViewQtDelegate() { } virtual void initAsPopup(const QRect&) = 0; - virtual QRectF screenRect() const = 0; - virtual QRectF contentsRect() const = 0; + virtual QRectF viewGeometry() const = 0; + virtual QRect windowGeometry() const = 0; virtual void setKeyboardFocus() = 0; virtual bool hasKeyboardFocus() = 0; virtual void lockMouse() = 0; diff --git a/src/core/renderer/content_renderer_client_qt.cpp b/src/core/renderer/content_renderer_client_qt.cpp index 403448b91..5fd4c7d65 100644 --- a/src/core/renderer/content_renderer_client_qt.cpp +++ b/src/core/renderer/content_renderer_client_qt.cpp @@ -40,6 +40,8 @@ #include "renderer/content_renderer_client_qt.h" #include "common/qt_messages.h" +#include "extensions/buildflags/buildflags.h" +#include "printing/buildflags/buildflags.h" #include "renderer/content_settings_observer_qt.h" #include "base/strings/string_split.h" #if QT_CONFIG(webengine_spellchecker) @@ -66,7 +68,8 @@ #include "media/base/key_system_properties.h" #include "media/media_buildflags.h" #include "net/base/net_errors.h" -#include "services/service_manager/public/cpp/service_context.h" +#include "services/service_manager/public/cpp/connector.h" +#include "services/service_manager/public/cpp/interface_provider.h" #include "third_party/blink/public/platform/web_url_error.h" #include "third_party/blink/public/platform/web_url_request.h" #include "third_party/blink/public/web/web_security_policy.h" @@ -81,10 +84,17 @@ #include "renderer/render_frame_observer_qt.h" #include "renderer/render_view_observer_qt.h" +#include "renderer/render_thread_observer_qt.h" #include "renderer/user_resource_controller.h" #if QT_CONFIG(webengine_webchannel) #include "renderer/web_channel_ipc_transport.h" #endif + +#if BUILDFLAG(ENABLE_EXTENSIONS) +#include "common/extensions/extensions_client_qt.h" +#include "extensions/extensions_renderer_client_qt.h" +#endif //ENABLE_EXTENSIONS + #include "services/service_manager/public/cpp/binder_registry.h" #include "services/service_manager/public/cpp/connector.h" @@ -95,9 +105,8 @@ #include "content/public/renderer/key_system_support.h" #include "media/base/media_switches.h" #include "media/base/video_codecs.h" +#include "third_party/widevine/cdm/buildflags.h" #include "third_party/widevine/cdm/widevine_cdm_common.h" - -#include "widevine_cdm_version.h" // In SHARED_INTERMEDIATE_DIR. #endif namespace QtWebEngineCore { @@ -105,7 +114,12 @@ namespace QtWebEngineCore { static const char kHttpErrorDomain[] = "http"; ContentRendererClientQt::ContentRendererClientQt() + : m_serviceBinding(this) { +#if BUILDFLAG(ENABLE_EXTENSIONS) + extensions::ExtensionsClient::Set(extensions::ExtensionsClientQt::GetInstance()); + extensions::ExtensionsRendererClient::Set(ExtensionsRendererClientQt::GetInstance()); +#endif } ContentRendererClientQt::~ContentRendererClientQt() @@ -116,6 +130,7 @@ void ContentRendererClientQt::RenderThreadStarted() { content::RenderThread *renderThread = content::RenderThread::Get(); (void)GetConnector(); + m_renderThreadObserver.reset(new RenderThreadObserverQt()); m_visitedLinkSlave.reset(new visitedlink::VisitedLinkSlave); m_webCacheImpl.reset(new web_cache::WebCacheImpl()); @@ -127,6 +142,7 @@ void ContentRendererClientQt::RenderThreadStarted() content::ChildThread::Get()->GetServiceManagerConnection()->AddConnectionFilter( std::make_unique<content::SimpleConnectionFilter>(std::move(registry))); + renderThread->AddObserver(m_renderThreadObserver.data()); renderThread->AddObserver(UserResourceController::instance()); #if QT_CONFIG(webengine_spellchecker) @@ -137,7 +153,18 @@ void ContentRendererClientQt::RenderThreadStarted() // Allow XMLHttpRequests from qrc to file. blink::WebURL qrc(blink::KURL("qrc:")); blink::WebString file(blink::WebString::FromASCII("file")); - blink::WebSecurityPolicy::AddOriginAccessWhitelistEntry(qrc, file, blink::WebString(), true); + blink::WebSecurityPolicy::AddOriginAccessAllowListEntry(qrc, file, blink::WebString(), true, + network::mojom::CorsOriginAccessMatchPriority::kDefaultPriority); + +#if BUILDFLAG(ENABLE_EXTENSIONS) + // Allow the pdf viewer extension to access chrome resources + blink::WebURL pdfViewerExtension(blink::KURL("chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai")); + blink::WebString chromeResources(blink::WebString::FromASCII("chrome")); + blink::WebSecurityPolicy::AddOriginAccessAllowListEntry(pdfViewerExtension, chromeResources, blink::WebString(), true, + network::mojom::CorsOriginAccessMatchPriority::kDefaultPriority); + + ExtensionsRendererClientQt::GetInstance()->RenderThreadStarted(); +#endif } void ContentRendererClientQt::RenderViewCreated(content::RenderView* render_view) @@ -149,11 +176,12 @@ void ContentRendererClientQt::RenderViewCreated(content::RenderView* render_view void ContentRendererClientQt::RenderFrameCreated(content::RenderFrame* render_frame) { - new QtWebEngineCore::RenderFrameObserverQt(render_frame); + QtWebEngineCore::RenderFrameObserverQt *render_frame_observer = new QtWebEngineCore::RenderFrameObserverQt(render_frame); #if QT_CONFIG(webengine_webchannel) if (render_frame->IsMainFrame()) new WebChannelIPCTransport(render_frame); #endif + UserResourceController::instance()->renderFrameCreated(render_frame); new QtWebEngineCore::ContentSettingsObserverQt(render_frame); @@ -166,17 +194,41 @@ void ContentRendererClientQt::RenderFrameCreated(content::RenderFrame* render_fr render_frame, base::WrapUnique(new PrintWebViewHelperDelegateQt())); #endif // QT_CONFIG(webengine_printing_and_pdf) +#if BUILDFLAG(ENABLE_EXTENSIONS) + auto registry = std::make_unique<service_manager::BinderRegistry>(); + ExtensionsRendererClientQt::GetInstance()->RenderFrameCreated(render_frame, render_frame_observer->registry()); +#endif +} + +void ContentRendererClientQt::RunScriptsAtDocumentStart(content::RenderFrame *render_frame) +{ +#if BUILDFLAG(ENABLE_EXTENSIONS) + ExtensionsRendererClientQt::GetInstance()->RunScriptsAtDocumentStart(render_frame); + // |render_frame| might be dead by now. +#endif } -void ContentRendererClientQt::RunScriptsAtDocumentEnd(content::RenderFrame* render_frame) +void ContentRendererClientQt::RunScriptsAtDocumentEnd(content::RenderFrame *render_frame) { // Check whether the render_frame has been created and has not been detached yet. // Otherwise the WebFrame is not available. RenderFrameObserverQt *render_frame_observer = RenderFrameObserverQt::Get(render_frame); - if (!render_frame_observer || render_frame_observer->isFrameDetached()) - return; // The frame is invisible to scripts. - UserResourceController::instance()->RunScriptsAtDocumentEnd(render_frame); + if (render_frame_observer && !render_frame_observer->isFrameDetached()) + UserResourceController::instance()->RunScriptsAtDocumentEnd(render_frame); + +#if BUILDFLAG(ENABLE_EXTENSIONS) + ExtensionsRendererClientQt::GetInstance()->RunScriptsAtDocumentEnd(render_frame); + // |render_frame| might be dead by now. +#endif +} + +void ContentRendererClientQt::RunScriptsAtDocumentIdle(content::RenderFrame *render_frame) +{ +#if BUILDFLAG(ENABLE_EXTENSIONS) + ExtensionsRendererClientQt::GetInstance()->RunScriptsAtDocumentIdle(render_frame); + // |render_frame| might be dead by now. +#endif } bool ContentRendererClientQt::HasErrorPage(int httpStatusCode) @@ -195,28 +247,35 @@ bool ContentRendererClientQt::ShouldSuppressErrorPage(content::RenderFrame *fram } // To tap into the chromium localized strings. Ripped from the chrome layer (highly simplified). -void ContentRendererClientQt::PrepareErrorPage(content::RenderFrame* renderFrame, const blink::WebURLRequest &failedRequest, +void ContentRendererClientQt::PrepareErrorPage(content::RenderFrame *renderFrame, const blink::WebURLError &web_error, - std::string *errorHtml, base::string16 *errorDescription) + const std::string &httpMethod, + bool ignoring_cache, + std::string *errorHtml) { - GetNavigationErrorStringsInternal(renderFrame, failedRequest, + Q_UNUSED(ignoring_cache); + GetNavigationErrorStringsInternal(renderFrame, httpMethod, error_page::Error::NetError(web_error.url(), web_error.reason(), web_error.has_copy_in_cache()), - errorHtml, errorDescription); + errorHtml); } -void ContentRendererClientQt::PrepareErrorPageForHttpStatusError(content::RenderFrame* renderFrame, const blink::WebURLRequest& failedRequest, - const GURL& unreachable_url, int http_status, - std::string* errorHtml, base::string16* errorDescription) +void ContentRendererClientQt::PrepareErrorPageForHttpStatusError(content::RenderFrame *renderFrame, + const GURL &unreachable_url, + const std::string &httpMethod, + bool ignoring_cache, + int http_status, + std::string *errorHtml) { - GetNavigationErrorStringsInternal(renderFrame, failedRequest, + Q_UNUSED(ignoring_cache); + GetNavigationErrorStringsInternal(renderFrame, httpMethod, error_page::Error::HttpError(unreachable_url, http_status), - errorHtml, errorDescription); + errorHtml); } -void ContentRendererClientQt::GetNavigationErrorStringsInternal(content::RenderFrame *renderFrame, const blink::WebURLRequest &failedRequest, const error_page::Error &error, std::string *errorHtml, base::string16 *errorDescription) +void ContentRendererClientQt::GetNavigationErrorStringsInternal(content::RenderFrame *renderFrame, const std::string &httpMethod, const error_page::Error &error, std::string *errorHtml) { Q_UNUSED(renderFrame) - const bool isPost = QByteArray::fromStdString(failedRequest.HttpMethod().Utf8()) == QByteArrayLiteral("POST"); + const bool isPost = QByteArray::fromStdString(httpMethod) == QByteArrayLiteral("POST"); if (errorHtml) { // Use a local error page. @@ -229,8 +288,9 @@ void ContentRendererClientQt::GetNavigationErrorStringsInternal(content::RenderF error_page::LocalizedError::GetStrings( error.reason(), error.domain(), error.url(), isPost, - error.stale_copy_in_cache(), false, false, - locale, std::unique_ptr<error_page::ErrorPageParams>(), &errorStrings); + error.stale_copy_in_cache(), false, RenderThreadObserverQt::is_incognito_process(), + error_page::LocalizedError::OfflineContentOnNetErrorFeatureState::kDisabled, + false, locale, std::unique_ptr<error_page::ErrorPageParams>(), &errorStrings); resourceId = IDR_NET_ERROR_HTML; const base::StringPiece template_html(ui::ResourceBundle::GetSharedInstance().GetRawDataResource(resourceId)); @@ -239,9 +299,6 @@ void ContentRendererClientQt::GetNavigationErrorStringsInternal(content::RenderF else // "t" is the id of the templates root node. *errorHtml = webui::GetTemplatesHtml(template_html, &errorStrings, "t"); } - - if (errorDescription) - *errorDescription = error_page::LocalizedError::GetErrorDetails(error.domain(), error.reason(), isPost); } unsigned long long ContentRendererClientQt::VisitedLinkHash(const char *canonicalUrl, size_t length) @@ -259,9 +316,27 @@ blink::WebPrescientNetworking *ContentRendererClientQt::GetPrescientNetworking() return m_prescientNetworkingDispatcher.get(); } -void ContentRendererClientQt::OnStart() +bool ContentRendererClientQt::OverrideCreatePlugin( + content::RenderFrame* render_frame, + const blink::WebPluginParams& params, blink::WebPlugin** plugin) +{ +#if BUILDFLAG(ENABLE_EXTENSIONS) + if (!ExtensionsRendererClientQt::GetInstance()->OverrideCreatePlugin(render_frame, params)) + return false; +#endif //ENABLE_EXTENSIONS + return content::ContentRendererClient::OverrideCreatePlugin(render_frame, params, plugin); +} + +content::BrowserPluginDelegate* ContentRendererClientQt::CreateBrowserPluginDelegate(content::RenderFrame *render_frame, + const content::WebPluginInfo &info, + const std::string &mime_type, + const GURL &original_url) { - context()->connector()->BindConnectorRequest(std::move(m_connectorRequest)); +#if BUILDFLAG(ENABLE_EXTENSIONS) + return ExtensionsRendererClientQt::GetInstance()->CreateBrowserPluginDelegate(render_frame, info, mime_type, original_url); +#else + return nullptr; +#endif } void ContentRendererClientQt::OnBindInterface(const service_manager::BindSourceInfo &remote_info, @@ -274,11 +349,9 @@ void ContentRendererClientQt::OnBindInterface(const service_manager::BindSourceI void ContentRendererClientQt::GetInterface(const std::string &interface_name, mojo::ScopedMessagePipeHandle interface_pipe) { - if (!m_connector) - return; - m_connector->BindInterface(service_manager::Identity("qtwebengine"), - interface_name, - std::move(interface_pipe)); + m_serviceBinding.GetConnector()->BindInterface( + service_manager::ServiceFilter::ByName("qtwebengine"), + interface_name, std::move(interface_pipe)); } // The following is based on chrome/renderer/media/chrome_key_systems.cc: @@ -373,7 +446,7 @@ static void AddExternalClearKey(std::vector<std::unique_ptr<media::KeySystemProp kExternalClearKeyCdmProxyTestKeySystem)); } -#if defined(WIDEVINE_CDM_AVAILABLE) +#if BUILDFLAG(ENABLE_WIDEVINE) static media::SupportedCodecs GetSupportedCodecs(const std::vector<media::VideoCodec> &supported_video_codecs, bool is_secure) { media::SupportedCodecs supported_codecs = media::EME_CODEC_NONE; @@ -385,11 +458,11 @@ static media::SupportedCodecs GetSupportedCodecs(const std::vector<media::VideoC // TODO(sandersd): Distinguish these from those that are directly supported, // as those may offer a higher level of protection. if (!supported_video_codecs.empty() || !is_secure) { - supported_codecs |= media::EME_CODEC_WEBM_OPUS; - supported_codecs |= media::EME_CODEC_WEBM_VORBIS; - supported_codecs |= media::EME_CODEC_MP4_FLAC; + supported_codecs |= media::EME_CODEC_OPUS; + supported_codecs |= media::EME_CODEC_VORBIS; + supported_codecs |= media::EME_CODEC_FLAC; #if BUILDFLAG(USE_PROPRIETARY_CODECS) - supported_codecs |= media::EME_CODEC_MP4_AAC; + supported_codecs |= media::EME_CODEC_AAC; #endif // BUILDFLAG(USE_PROPRIETARY_CODECS) } @@ -397,15 +470,15 @@ static media::SupportedCodecs GetSupportedCodecs(const std::vector<media::VideoC for (const auto &codec : supported_video_codecs) { switch (codec) { case media::VideoCodec::kCodecVP8: - supported_codecs |= media::EME_CODEC_WEBM_VP8; + supported_codecs |= media::EME_CODEC_VP8; break; case media::VideoCodec::kCodecVP9: - supported_codecs |= media::EME_CODEC_WEBM_VP9; - supported_codecs |= media::EME_CODEC_COMMON_VP9; + supported_codecs |= media::EME_CODEC_VP9_PROFILE0; + supported_codecs |= media::EME_CODEC_VP9_PROFILE2; break; #if BUILDFLAG(USE_PROPRIETARY_CODECS) case media::VideoCodec::kCodecH264: - supported_codecs |= media::EME_CODEC_MP4_AVC1; + supported_codecs |= media::EME_CODEC_AVC1; break; #endif // BUILDFLAG(USE_PROPRIETARY_CODECS) default: @@ -464,7 +537,7 @@ static void AddWidevine(std::vector<std::unique_ptr<media::KeySystemProperties>> persistent_license_support, persistent_usage_record_support, persistent_state_support, distinctive_identifier_support)); } -#endif // defined(WIDEVINE_CDM_AVAILABLE) +#endif // BUILDFLAG(ENABLE_WIDEVINE) #endif // BUILDFLAG(ENABLE_LIBRARY_CDMS) void ContentRendererClientQt::AddSupportedKeySystems(std::vector<std::unique_ptr<media::KeySystemProperties>> *key_systems) @@ -473,9 +546,9 @@ void ContentRendererClientQt::AddSupportedKeySystems(std::vector<std::unique_ptr if (base::FeatureList::IsEnabled(media::kExternalClearKeyForTesting)) AddExternalClearKey(key_systems); -#if defined(WIDEVINE_CDM_AVAILABLE) +#if BUILDFLAG(ENABLE_WIDEVINE) AddWidevine(key_systems); -#endif // defined(WIDEVINE_CDM_AVAILABLE) +#endif // BUILDFLAG(ENABLE_WIDEVINE) #endif // BUILDFLAG(ENABLE_LIBRARY_CDMS) } @@ -487,18 +560,30 @@ void ContentRendererClientQt::InitSpellCheck() } #endif +void ContentRendererClientQt::WillSendRequest(blink::WebLocalFrame *frame, + ui::PageTransition transition_type, + const blink::WebURL &url, + const url::Origin *initiator_origin, + GURL *new_url, + bool *attach_same_site_cookies) +{ +#if BUILDFLAG(ENABLE_EXTENSIONS) + ExtensionsRendererClientQt::GetInstance()->WillSendRequest(frame, transition_type, url, initiator_origin, new_url, attach_same_site_cookies); + if (!new_url->is_empty()) + return; +#endif + content::ContentRendererClient::WillSendRequest(frame, transition_type, url, initiator_origin, new_url, attach_same_site_cookies); +} + void ContentRendererClientQt::CreateRendererService(service_manager::mojom::ServiceRequest service_request) { - m_serviceContext = std::make_unique<service_manager::ServiceContext>( - std::make_unique<service_manager::ForwardingService>(this), - std::move(service_request)); + DCHECK(!m_serviceBinding.is_bound()); + m_serviceBinding.Bind(std::move(service_request)); } service_manager::Connector* ContentRendererClientQt::GetConnector() { - if (!m_connector) - m_connector = service_manager::Connector::Create(&m_connectorRequest); - return m_connector.get(); + return m_serviceBinding.GetConnector(); } } // namespace diff --git a/src/core/renderer/content_renderer_client_qt.h b/src/core/renderer/content_renderer_client_qt.h index 2a353caa6..dd164fa3a 100644 --- a/src/core/renderer/content_renderer_client_qt.h +++ b/src/core/renderer/content_renderer_client_qt.h @@ -46,6 +46,7 @@ #include "services/service_manager/public/cpp/connector.h" #include "services/service_manager/public/cpp/local_interface_provider.h" #include "services/service_manager/public/cpp/service.h" +#include "services/service_manager/public/cpp/service_binding.h" #include <QScopedPointer> @@ -71,6 +72,8 @@ class SpellCheck; namespace QtWebEngineCore { +class RenderThreadObserverQt; + class ContentRendererClientQt : public content::ContentRendererClient , public service_manager::Service , public service_manager::LocalInterfaceProvider @@ -85,18 +88,38 @@ public: void RenderFrameCreated(content::RenderFrame* render_frame) override; bool ShouldSuppressErrorPage(content::RenderFrame *, const GURL &) override; bool HasErrorPage(int http_status_code) override; - void PrepareErrorPage(content::RenderFrame* renderFrame, const blink::WebURLRequest& failedRequest, - const blink::WebURLError& error, std::string* errorHtml, base::string16* errorDescription) override; - void PrepareErrorPageForHttpStatusError(content::RenderFrame* render_frame, const blink::WebURLRequest& failed_request, - const GURL& unreachable_url, int http_status, - std::string* error_html, base::string16* error_description) override; + + void PrepareErrorPage(content::RenderFrame *render_frame, + const blink::WebURLError &error, + const std::string &http_method, + bool ignoring_cache, + std::string *error_html) override; + void PrepareErrorPageForHttpStatusError(content::RenderFrame *render_frame, + const GURL &unreachable_url, + const std::string &http_method, + bool ignoring_cache, + int http_status, + std::string *error_html) override; unsigned long long VisitedLinkHash(const char *canonicalUrl, size_t length) override; bool IsLinkVisited(unsigned long long linkHash) override; blink::WebPrescientNetworking* GetPrescientNetworking() override; void AddSupportedKeySystems(std::vector<std::unique_ptr<media::KeySystemProperties>>* key_systems) override; - void RunScriptsAtDocumentEnd(content::RenderFrame* render_frame) override; + void RunScriptsAtDocumentStart(content::RenderFrame *render_frame) override; + void RunScriptsAtDocumentEnd(content::RenderFrame *render_frame) override; + void RunScriptsAtDocumentIdle(content::RenderFrame *render_frame) override; + bool OverrideCreatePlugin(content::RenderFrame* render_frame, + const blink::WebPluginParams& params, blink::WebPlugin** plugin) override; + content::BrowserPluginDelegate* CreateBrowserPluginDelegate(content::RenderFrame* render_frame, + const content::WebPluginInfo& info, const std::string& mime_type, const GURL& original_url) override; + + void WillSendRequest(blink::WebLocalFrame *frame, + ui::PageTransition transition_type, + const blink::WebURL &url, + const url::Origin *initiator_origin, + GURL *new_url, + bool *attach_same_site_cookies) override; void CreateRendererService(service_manager::mojom::ServiceRequest service_request) override; @@ -107,7 +130,6 @@ private: service_manager::Connector *GetConnector(); // service_manager::Service: - void OnStart() override; void OnBindInterface(const service_manager::BindSourceInfo &remote_info, const std::string &name, mojo::ScopedMessagePipeHandle handle) override; @@ -115,18 +137,18 @@ private: // service_manager::LocalInterfaceProvider: void GetInterface(const std::string& name, mojo::ScopedMessagePipeHandle request_handle) override; - void GetNavigationErrorStringsInternal(content::RenderFrame* renderFrame, const blink::WebURLRequest& failedRequest, - const error_page::Error& error, std::string* errorHtml, base::string16* errorDescription); + void GetNavigationErrorStringsInternal(content::RenderFrame* renderFrame, const std::string &httpMethod, + const error_page::Error& error, std::string* errorHtml); + QScopedPointer<RenderThreadObserverQt> m_renderThreadObserver; QScopedPointer<visitedlink::VisitedLinkSlave> m_visitedLinkSlave; QScopedPointer<web_cache::WebCacheImpl> m_webCacheImpl; #if QT_CONFIG(webengine_spellchecker) QScopedPointer<SpellCheck> m_spellCheck; #endif - std::unique_ptr<service_manager::Connector> m_connector; service_manager::mojom::ConnectorRequest m_connectorRequest; - std::unique_ptr<service_manager::ServiceContext> m_serviceContext; + service_manager::ServiceBinding m_serviceBinding; service_manager::BinderRegistry m_registry; std::unique_ptr<network_hints::PrescientNetworkingDispatcher> m_prescientNetworkingDispatcher; diff --git a/src/core/renderer/content_settings_observer_qt.cpp b/src/core/renderer/content_settings_observer_qt.cpp index 045098457..98954eb4a 100644 --- a/src/core/renderer/content_settings_observer_qt.cpp +++ b/src/core/renderer/content_settings_observer_qt.cpp @@ -93,8 +93,8 @@ bool ContentSettingsObserverQt::OnMessageReceived(const IPC::Message& message) return handled; } -void ContentSettingsObserverQt::DidCommitProvisionalLoad(bool /*is_new_navigation*/, - bool is_same_document_navigation) +void ContentSettingsObserverQt::DidCommitProvisionalLoad(bool is_same_document_navigation, + ui::PageTransition /*transition*/) { blink::WebLocalFrame* frame = render_frame()->GetWebFrame(); if (frame->Parent()) @@ -151,8 +151,7 @@ void ContentSettingsObserverQt::RequestFileSystemAccessAsync(const WebContentSet url::Origin(frame->Top()->GetSecurityOrigin()).GetURL())); } -bool ContentSettingsObserverQt::AllowIndexedDB(const WebString &name, - const WebSecurityOrigin &/*origin*/) +bool ContentSettingsObserverQt::AllowIndexedDB(const WebSecurityOrigin &origin) { blink::WebFrame *frame = render_frame()->GetWebFrame(); if (IsUniqueFrame(frame)) @@ -160,8 +159,8 @@ bool ContentSettingsObserverQt::AllowIndexedDB(const WebString &name, bool result = false; Send(new QtWebEngineHostMsg_AllowIndexedDB( - routing_id(), url::Origin(frame->GetSecurityOrigin()).GetURL(), - url::Origin(frame->Top()->GetSecurityOrigin()).GetURL(), name.Utf16(), + routing_id(), url::Origin(origin).GetURL(), + url::Origin(frame->Top()->GetSecurityOrigin()).GetURL(), &result)); return result; } diff --git a/src/core/renderer/content_settings_observer_qt.h b/src/core/renderer/content_settings_observer_qt.h index 981655f20..69b0eda9e 100644 --- a/src/core/renderer/content_settings_observer_qt.h +++ b/src/core/renderer/content_settings_observer_qt.h @@ -72,16 +72,15 @@ public: const blink::WebString &display_name, unsigned estimated_size) override; void RequestFileSystemAccessAsync(const blink::WebContentSettingCallbacks &callbacks) override; - bool AllowIndexedDB(const blink::WebString &name, - const blink::WebSecurityOrigin &origin) override; + bool AllowIndexedDB(const blink::WebSecurityOrigin &origin) override; bool AllowStorage(bool local) override; private: // RenderFrameObserver implementation: bool OnMessageReceived(const IPC::Message &message) override; - void DidCommitProvisionalLoad(bool is_new_navigation, - bool is_same_document_navigation) override; + void DidCommitProvisionalLoad(bool is_same_document_navigation, + ui::PageTransition transition) override; void OnDestruct() override; // Message handlers. diff --git a/src/core/chromium_overrides.h b/src/core/renderer/extensions/extensions_dispatcher_delegate_qt.cpp index b27bf309c..418429330 100644 --- a/src/core/chromium_overrides.h +++ b/src/core/renderer/extensions/extensions_dispatcher_delegate_qt.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtWebEngine module of the Qt Toolkit. @@ -37,18 +37,16 @@ ** ****************************************************************************/ -#ifndef CHROMIUM_OVERRIDES_H -#define CHROMIUM_OVERRIDES_H +#include "extensions_dispatcher_delegate_qt.h" -#include "content/public/common/screen_info.h" -#include <QtGlobal> +namespace QtWebEngineCore { -QT_BEGIN_NAMESPACE -class QWindow; -QT_END_NAMESPACE +ExtensionsDispatcherDelegateQt::ExtensionsDispatcherDelegateQt() +{ +} -namespace QtWebEngineCore { -void GetScreenInfoFromNativeWindow(QWindow* window, content::ScreenInfo* results); +ExtensionsDispatcherDelegateQt::~ExtensionsDispatcherDelegateQt() +{ } -#endif +} //namespace QtWebEngineCore diff --git a/src/core/renderer/extensions/extensions_dispatcher_delegate_qt.h b/src/core/renderer/extensions/extensions_dispatcher_delegate_qt.h new file mode 100644 index 000000000..25aa18e71 --- /dev/null +++ b/src/core/renderer/extensions/extensions_dispatcher_delegate_qt.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef EXTENSIONSDISPATCHERDELEGATEQT_H +#define EXTENSIONSDISPATCHERDELEGATEQT_H + +#include "base/macros.h" +#include "extensions/renderer/dispatcher_delegate.h" + +namespace QtWebEngineCore { + +class ExtensionsDispatcherDelegateQt : public extensions::DispatcherDelegate +{ +public: + ExtensionsDispatcherDelegateQt(); + ~ExtensionsDispatcherDelegateQt() override; + +private: + DISALLOW_COPY_AND_ASSIGN(ExtensionsDispatcherDelegateQt); +}; + +} // namespace QtWebEngineCore + +#endif // EXTENSIONSDISPATCHERDELEGATEQT_H diff --git a/src/core/renderer/extensions/extensions_renderer_client_qt.cpp b/src/core/renderer/extensions/extensions_renderer_client_qt.cpp new file mode 100644 index 000000000..c25494590 --- /dev/null +++ b/src/core/renderer/extensions/extensions_renderer_client_qt.cpp @@ -0,0 +1,205 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// based on chrome/renderer/extensions/chrome_extensions_renderer_client.cc: +// Copyright (c) 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "extensions_renderer_client_qt.h" + +#include "extensions_dispatcher_delegate_qt.h" +#include "renderer/render_thread_observer_qt.h" +#include "renderer_permissions_policy_delegate_qt.h" +#include "resource_request_policy_qt.h" + +#include "base/command_line.h" +#include "base/lazy_instance.h" +#include "content/public/common/content_constants.h" +#include "content/public/common/content_switches.h" +#include "content/public/renderer/render_frame.h" +#include "content/public/renderer/render_thread.h" +#include "extensions/common/constants.h" +#include "extensions/common/switches.h" +#include "extensions/renderer/dispatcher.h" +#include "extensions/renderer/extension_frame_helper.h" +#include "extensions/renderer/extensions_render_frame_observer.h" +#include "extensions/renderer/guest_view/extensions_guest_view_container.h" +#include "extensions/renderer/guest_view/extensions_guest_view_container_dispatcher.h" +#include "extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container.h" +#include "extensions/renderer/renderer_extension_registry.h" +#include "extensions/renderer/script_context.h" +#include "third_party/blink/public/platform/web_url.h" +#include "third_party/blink/public/web/web_plugin_params.h" + +namespace chrome { +const char kExtensionInvalidRequestURL[] = "chrome-extension://invalid/"; +const char kExtensionResourceInvalidRequestURL[] = "chrome-extension-resource://invalid/"; +} + +namespace QtWebEngineCore { + +ExtensionsRendererClientQt::ExtensionsRendererClientQt() +{ +} + +ExtensionsRendererClientQt::~ExtensionsRendererClientQt() +{ +} + +// Returns true if the current render process was launched incognito. +bool ExtensionsRendererClientQt::IsIncognitoProcess() const +{ + return RenderThreadObserverQt::is_incognito_process(); +} + +// Returns the lowest isolated world ID available to extensions. +// Must be greater than 0. See blink::WebFrame::executeScriptInIsolatedWorld +// (third_party/WebKit/public/web/WebFrame.h) for additional context. +int ExtensionsRendererClientQt::GetLowestIsolatedWorldId() const +{ + return 257; +} + +// static +ExtensionsRendererClientQt *ExtensionsRendererClientQt::GetInstance() +{ + static base::LazyInstance<ExtensionsRendererClientQt>::Leaky client = + LAZY_INSTANCE_INITIALIZER; + return client.Pointer(); +} + +extensions::Dispatcher *ExtensionsRendererClientQt::GetDispatcher() +{ + return extension_dispatcher_.get(); +} + +void ExtensionsRendererClientQt::OnExtensionLoaded(const extensions::Extension &extension) +{ + resource_request_policy_->OnExtensionLoaded(extension); +} + +void ExtensionsRendererClientQt::OnExtensionUnloaded(const extensions::ExtensionId &extension_id) +{ + resource_request_policy_->OnExtensionUnloaded(extension_id); +} + +void ExtensionsRendererClientQt::RenderThreadStarted() +{ + content::RenderThread *thread = content::RenderThread::Get(); + // ChromeRenderViewTest::SetUp() creates its own ExtensionDispatcher and + // injects it using SetExtensionDispatcher(). Don't overwrite it. + if (!extension_dispatcher_) + extension_dispatcher_.reset(new extensions::Dispatcher(std::make_unique<ExtensionsDispatcherDelegateQt>())); + extension_dispatcher_->OnRenderThreadStarted(thread); + permissions_policy_delegate_.reset(new RendererPermissionsPolicyDelegateQt(extension_dispatcher_.get())); + resource_request_policy_.reset(new extensions::ResourceRequestPolicyQt(extension_dispatcher_.get())); + guest_view_container_dispatcher_.reset(new extensions::ExtensionsGuestViewContainerDispatcher()); + + thread->AddObserver(extension_dispatcher_.get()); + thread->AddObserver(guest_view_container_dispatcher_.get()); +} + +void ExtensionsRendererClientQt::RenderFrameCreated(content::RenderFrame *render_frame, + service_manager::BinderRegistry *registry) +{ + new extensions::ExtensionsRenderFrameObserver(render_frame, registry); + new extensions::ExtensionFrameHelper(render_frame, + extension_dispatcher_.get()); + extension_dispatcher_->OnRenderFrameCreated(render_frame); +} + +bool ExtensionsRendererClientQt::OverrideCreatePlugin(content::RenderFrame *render_frame, + const blink::WebPluginParams ¶ms) +{ + if (params.mime_type.Utf8() != content::kBrowserPluginMimeType) + return true; + bool guest_view_api_available = false; + return !guest_view_api_available; +} + +void ExtensionsRendererClientQt::WillSendRequest(blink::WebLocalFrame *frame, + ui::PageTransition transition_type, + const blink::WebURL &url, + const url::Origin *initiator_origin, + GURL *new_url, + bool *attach_same_site_cookies) +{ + if (url.ProtocolIs(extensions::kExtensionScheme) && + !resource_request_policy_->CanRequestResource(url, frame, transition_type)) { + *new_url = GURL(chrome::kExtensionInvalidRequestURL); + } +} + +bool ExtensionsRendererClientQt::ShouldFork(blink::WebLocalFrame *frame, + const GURL &url, + bool is_initial_navigation, + bool is_server_redirect, + bool *send_referrer) +{ + return false; // TODO: Fix this to a sensible value +} + +content::BrowserPluginDelegate *ExtensionsRendererClientQt::CreateBrowserPluginDelegate(content::RenderFrame *render_frame, + const content::WebPluginInfo &info, + const std::string &mime_type, + const GURL &original_url) +{ + if (mime_type == content::kBrowserPluginMimeType) + return new extensions::ExtensionsGuestViewContainer(render_frame); + return new extensions::MimeHandlerViewContainer(render_frame, info, mime_type, original_url); +} + +void ExtensionsRendererClientQt::RunScriptsAtDocumentStart(content::RenderFrame *render_frame) +{ + extension_dispatcher_->RunScriptsAtDocumentStart(render_frame); +} + +void ExtensionsRendererClientQt::RunScriptsAtDocumentEnd(content::RenderFrame *render_frame) +{ + extension_dispatcher_->RunScriptsAtDocumentEnd(render_frame); +} + +void ExtensionsRendererClientQt::RunScriptsAtDocumentIdle(content::RenderFrame *render_frame) +{ + extension_dispatcher_->RunScriptsAtDocumentIdle(render_frame); +} + + +} // namespace QtWebEngineCore diff --git a/src/core/renderer/extensions/extensions_renderer_client_qt.h b/src/core/renderer/extensions/extensions_renderer_client_qt.h new file mode 100644 index 000000000..2d45d255a --- /dev/null +++ b/src/core/renderer/extensions/extensions_renderer_client_qt.h @@ -0,0 +1,135 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef EXTENSIONSRENDERERCLIENTQT_H +#define EXTENSIONSRENDERERCLIENTQT_H + +#include <memory> +#include <string> + +#include "base/macros.h" +#include "extensions/renderer/extensions_renderer_client.h" +#include "services/service_manager/public/cpp/binder_registry.h" +#include "ui/base/page_transition_types.h" + +class GURL; + +namespace blink { +class WebLocalFrame; +struct WebPluginParams; +class WebURL; +} + +namespace content { +class BrowserPluginDelegate; +class RenderFrame; +class RenderView; +struct WebPluginInfo; +} + +namespace url { +class Origin; +} + +namespace extensions { +class Dispatcher; +class ExtensionsGuestViewContainerDispatcher; +class ResourceRequestPolicyQt; +} + +namespace QtWebEngineCore { + +class ExtensionsDispatcherDelegateQt; +class RendererPermissionsPolicyDelegateQt; + +class ExtensionsRendererClientQt : public extensions::ExtensionsRendererClient +{ +public: + ExtensionsRendererClientQt(); + ~ExtensionsRendererClientQt() override; + + // extensions::ExtensionsRendererClient implementation. + bool IsIncognitoProcess() const override; + int GetLowestIsolatedWorldId() const override; + extensions::Dispatcher *GetDispatcher() override; + void OnExtensionLoaded(const extensions::Extension &extension) override; + void OnExtensionUnloaded(const extensions::ExtensionId &extension_id) override; + + // Match ContentRendererClientQt's method names... + void RenderThreadStarted(); + void RenderFrameCreated(content::RenderFrame *, service_manager::BinderRegistry *); + bool OverrideCreatePlugin(content::RenderFrame *render_frame, + const blink::WebPluginParams ¶ms); + void WillSendRequest(blink::WebLocalFrame *frame, + ui::PageTransition transition_type, + const blink::WebURL &url, + const url::Origin *initiator_origin, + GURL *new_url, + bool *attach_same_site_cookies); + + static bool ShouldFork(blink::WebLocalFrame *frame, + const GURL &url, + bool is_initial_navigation, + bool is_server_redirect, + bool *send_referrer); + static content::BrowserPluginDelegate *CreateBrowserPluginDelegate(content::RenderFrame *render_frame, + const content::WebPluginInfo &info, + const std::string &mime_type, + const GURL &original_url); + + void RunScriptsAtDocumentStart(content::RenderFrame *render_frame); + void RunScriptsAtDocumentEnd(content::RenderFrame *render_frame); + void RunScriptsAtDocumentIdle(content::RenderFrame *render_frame); + + extensions::Dispatcher *extension_dispatcher() + { return extension_dispatcher_.get(); } + + static ExtensionsRendererClientQt *GetInstance(); + +private: + std::unique_ptr<ExtensionsDispatcherDelegateQt> extension_dispatcher_delegate_; + std::unique_ptr<RendererPermissionsPolicyDelegateQt> permissions_policy_delegate_; + std::unique_ptr<extensions::Dispatcher> extension_dispatcher_; + std::unique_ptr<extensions::ExtensionsGuestViewContainerDispatcher> guest_view_container_dispatcher_; + std::unique_ptr<extensions::ResourceRequestPolicyQt> resource_request_policy_; +}; + +} // namespace QtWebEngineCore + +#endif // EXTENSIONSRENDERERCLIENTQT_H diff --git a/src/core/renderer/extensions/renderer_permissions_policy_delegate_qt.cpp b/src/core/renderer/extensions/renderer_permissions_policy_delegate_qt.cpp new file mode 100644 index 000000000..39412b76c --- /dev/null +++ b/src/core/renderer/extensions/renderer_permissions_policy_delegate_qt.cpp @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "renderer_permissions_policy_delegate_qt.h" + +#include "extensions/common/constants.h" +#include "extensions/common/extensions_client.h" +#include "extensions/common/manifest_constants.h" +#include "extensions/common/switches.h" +#include "extensions/renderer/dispatcher.h" + +namespace QtWebEngineCore { + +RendererPermissionsPolicyDelegateQt::RendererPermissionsPolicyDelegateQt(extensions::Dispatcher *dispatcher) + : m_dispatcher(dispatcher) +{ + extensions::PermissionsData::SetPolicyDelegate(this); +} + +RendererPermissionsPolicyDelegateQt::~RendererPermissionsPolicyDelegateQt() +{ + extensions::PermissionsData::SetPolicyDelegate(nullptr); +} + +bool RendererPermissionsPolicyDelegateQt::IsRestrictedUrl(const GURL &, std::string *) +{ + return false; +} + +} // namespace QtWebEngineCore diff --git a/src/core/net/qrc_protocol_handler_qt.h b/src/core/renderer/extensions/renderer_permissions_policy_delegate_qt.h index f2849c1ef..e2af47657 100644 --- a/src/core/net/qrc_protocol_handler_qt.h +++ b/src/core/renderer/extensions/renderer_permissions_policy_delegate_qt.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtWebEngine module of the Qt Toolkit. @@ -37,34 +37,32 @@ ** ****************************************************************************/ -#ifndef QRC_PROTOCOL_HANDLER_QT_H_ -#define QRC_PROTOCOL_HANDLER_QT_H_ +#ifndef RENDERERPERMISSIONSPOLICYDELEGATEQT_H +#define RENDERERPERMISSIONSPOLICYDELEGATEQT_H -#include "net/url_request/url_request_job_factory.h" +#include "base/macros.h" +#include "extensions/common/permissions/permissions_data.h" -namespace net { - -class NetworkDelegate; -class URLRequestJob; - -} // namespace +namespace extensions { +class Dispatcher; +} namespace QtWebEngineCore { -extern const char kQrcSchemeQt[]; - -// Implements a ProtocolHandler for qrc file jobs. If |network_delegate_| is NULL, -// then all file requests will fail with ERR_ACCESS_DENIED. -class QrcProtocolHandlerQt : public net::URLRequestJobFactory::ProtocolHandler { - +class RendererPermissionsPolicyDelegateQt : public extensions::PermissionsData::PolicyDelegate +{ public: - QrcProtocolHandlerQt(); - net::URLRequestJob *MaybeCreateJob(net::URLRequest *request, net::NetworkDelegate *networkDelegate) const override; + explicit RendererPermissionsPolicyDelegateQt(extensions::Dispatcher *dispatcher); + ~RendererPermissionsPolicyDelegateQt() override; + + bool IsRestrictedUrl(const GURL &, std::string *) override; private: - DISALLOW_COPY_AND_ASSIGN(QrcProtocolHandlerQt); + extensions::Dispatcher *m_dispatcher; + + DISALLOW_COPY_AND_ASSIGN(RendererPermissionsPolicyDelegateQt); }; } // namespace QtWebEngineCore -#endif // QRC_PROTOCOL_HANDLER_QT_H_ +#endif // RENDERERPERMISSIONSPOLICYDELEGATEQT_H diff --git a/src/core/renderer/extensions/resource_request_policy_qt.cpp b/src/core/renderer/extensions/resource_request_policy_qt.cpp new file mode 100644 index 000000000..a64b1fef8 --- /dev/null +++ b/src/core/renderer/extensions/resource_request_policy_qt.cpp @@ -0,0 +1,183 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// based on chrome/renderer/extensions/resource_request_policy.cc: +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "resource_request_policy_qt.h" + +#include "base/strings/stringprintf.h" +#include "chrome/common/url_constants.h" +#include "extensions/common/constants.h" +#include "extensions/common/manifest_handlers/web_accessible_resources_info.h" +#include "extensions/common/manifest_handlers/webview_info.h" +#include "extensions/renderer/dispatcher.h" +#include "third_party/blink/public/mojom/devtools/console_message.mojom-shared.h" +#include "third_party/blink/public/web/web_console_message.h" +#include "third_party/blink/public/web/web_document.h" +#include "third_party/blink/public/web/web_local_frame.h" + +namespace extensions { +ResourceRequestPolicyQt::ResourceRequestPolicyQt(Dispatcher *dispatcher) + : m_dispatcher(dispatcher) +{ +} + +void ResourceRequestPolicyQt::OnExtensionLoaded(const Extension &extension) +{ + if (WebAccessibleResourcesInfo::HasWebAccessibleResources(&extension) + || WebviewInfo::HasWebviewAccessibleResources(extension, m_dispatcher->webview_partition_id()) +// // Hosted app icons are accessible. +// // TODO(devlin): Should we incorporate this into +// // WebAccessibleResourcesInfo? +// || (extension.is_hosted_app() && !IconsInfo::GetIcons(&extension).empty()) + ) { + m_web_accessible_ids.insert(extension.id()); + } +} + +void ResourceRequestPolicyQt::OnExtensionUnloaded(const ExtensionId &extension_id) +{ + m_web_accessible_ids.erase(extension_id); +} + +// Returns true if the chrome-extension:// |resource_url| can be requested +// from |frame_url|. In some cases this decision is made based upon how +// this request was generated. Web triggered transitions are more restrictive +// than those triggered through UI. +bool ResourceRequestPolicyQt::CanRequestResource(const GURL &resource_url, + blink::WebLocalFrame *frame, + ui::PageTransition transition_type) +{ + CHECK(resource_url.SchemeIs(kExtensionScheme)); + + GURL frame_url = frame->GetDocument().Url(); + + // The page_origin may be GURL("null") for unique origins like data URLs, + // but this is ok for the checks below. We only care if it matches the + // current extension or has a devtools scheme. + GURL page_origin = url::Origin(frame->Top()->GetSecurityOrigin()).GetURL(); + + GURL extension_origin = resource_url.GetOrigin(); + + // We always allow loads in the following cases, regardless of web accessible + // resources: + + // Empty urls (needed for some edge cases when we have empty urls). + if (frame_url.is_empty()) + return true; + + // Extensions requesting their own resources (frame_url check is for images, + // page_url check is for iframes). + // TODO(devlin): We should be checking the ancestor chain, not just the + // top-level frame. Additionally, we should be checking the security origin + // of the frame, to account for about:blank subframes being scripted by an + // extension parent (though we'll still need the frame origin check for + // sandboxed frames). + if (frame_url.GetOrigin() == extension_origin || page_origin == extension_origin) + return true; + + if (!ui::PageTransitionIsWebTriggerable(transition_type)) + return true; + + // Unreachable web page error page (to allow showing the icon of the + // unreachable app on this page). + if (frame_url == content::kUnreachableWebDataURL) + return true; + + bool is_dev_tools = page_origin.SchemeIs(content::kChromeDevToolsScheme); + // Note: we check |web_accessible_ids_| (rather than first looking up the + // extension in the registry and checking that) to be more resistant against + // timing attacks. This way, determining access for an extension that isn't + // installed takes the same amount of time as determining access for an + // extension with no web accessible resources. We aren't worried about any + // extensions with web accessible resources, since those are inherently + // identifiable. + if (!is_dev_tools && !m_web_accessible_ids.count(extension_origin.host())) + return false; + + const Extension* extension = RendererExtensionRegistry::Get()->GetExtensionOrAppByURL(resource_url); + if (is_dev_tools) { + // Allow the load in the case of a non-existent extension. We'll just get a + // 404 from the browser process. + // TODO(devlin): Can this happen? Does devtools potentially make requests + // to non-existent extensions? + if (!extension) + return true; +// // Devtools (chrome-extension:// URLs are loaded into frames of devtools to +// // support the devtools extension APIs). +// if (!chrome_manifest_urls::GetDevToolsPage(extension).is_empty()) +// return true; + } + + DCHECK(extension); + + // Disallow loading of packaged resources for hosted apps. We don't allow + // hybrid hosted/packaged apps. The one exception is access to icons, since + // some extensions want to be able to do things like create their own + // launchers. + base::StringPiece resource_root_relative_path = + resource_url.path_piece().empty() ? base::StringPiece() + : resource_url.path_piece().substr(1); + if (extension->is_hosted_app() /*&& !IconsInfo::GetIcons(extension).ContainsPath(resource_root_relative_path)*/) { + LOG(ERROR) << "Denying load of " << resource_url.spec() << " from " + << "hosted app."; + return false; + } + + // Disallow loading of extension resources which are not explicitly listed + // as web or WebView accessible if the manifest version is 2 or greater. + if (!WebAccessibleResourcesInfo::IsResourceWebAccessible(extension, resource_url.path()) && + !WebviewInfo::IsResourceWebviewAccessible(extension, m_dispatcher->webview_partition_id(), resource_url.path())) + { + std::string message = base::StringPrintf( + "Denying load of %s. Resources must be listed in the " + "web_accessible_resources manifest key in order to be loaded by " + "pages outside the extension.", + resource_url.spec().c_str()); + frame->AddMessageToConsole(blink::WebConsoleMessage(blink::mojom::ConsoleMessageLevel::kError, blink::WebString::FromUTF8(message))); + return false; + } + + return true; +} + +} // namespace extensions diff --git a/src/core/renderer/extensions/resource_request_policy_qt.h b/src/core/renderer/extensions/resource_request_policy_qt.h new file mode 100644 index 000000000..e6d4e79bb --- /dev/null +++ b/src/core/renderer/extensions/resource_request_policy_qt.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef RESOURCEREQUESTPOLICYQT_H +#define RESOURCEREQUESTPOLICYQT_H + +#include <set> + +#include "base/macros.h" +#include "extensions/common/extension_id.h" +#include "ui/base/page_transition_types.h" + +class GURL; + +namespace blink { +class WebLocalFrame; +} + +namespace extensions { + +class Dispatcher; +class Extension; + +// Encapsulates the policy for when chrome-extension:// and +// chrome-extension-resource:// URLs can be requested. +class ResourceRequestPolicyQt +{ +public: + explicit ResourceRequestPolicyQt(Dispatcher *dispatcher); + + void OnExtensionLoaded(const Extension &extension); + void OnExtensionUnloaded(const ExtensionId &extension); + + // Returns true if the chrome-extension:// |resource_url| can be requested + // from |frame_url|. In some cases this decision is made based upon how + // this request was generated. Web triggered transitions are more restrictive + // than those triggered through UI. + bool CanRequestResource(const GURL &resource_url, + blink::WebLocalFrame *frame, + ui::PageTransition transition_type); + +private: + Dispatcher *m_dispatcher; + + // The set of extension IDs with any potentially web- or webview-accessible + // resources. + std::set<ExtensionId> m_web_accessible_ids; + + DISALLOW_COPY_AND_ASSIGN(ResourceRequestPolicyQt); +}; +} // namespace extensions + +#endif // RESOURCEREQUESTPOLICYQT_H diff --git a/src/core/renderer/pepper/pepper_flash_renderer_host_qt.cpp b/src/core/renderer/pepper/pepper_flash_renderer_host_qt.cpp index 5d21201ba..9af05fd08 100644 --- a/src/core/renderer/pepper/pepper_flash_renderer_host_qt.cpp +++ b/src/core/renderer/pepper/pepper_flash_renderer_host_qt.cpp @@ -70,6 +70,7 @@ #include "third_party/skia/include/core/SkMatrix.h" #include "third_party/skia/include/core/SkPaint.h" #include "third_party/skia/include/core/SkPoint.h" +#include "third_party/skia/include/core/SkTextBlob.h" #include "third_party/skia/include/core/SkTypeface.h" #include "third_party/skia/include/private/SkTemplates.h" #include "ui/gfx/geometry/rect.h" @@ -299,14 +300,12 @@ int32_t PepperFlashRendererHostQt::OnDrawGlyphs( SkPaint paint; paint.setColor(params.color); - paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); - paint.setAntiAlias(true); - paint.setHinting(SkPaint::kFull_Hinting); - paint.setTextSize(SkIntToScalar(params.font_desc.size)); - paint.setTypeface(std::move(typeface)); + + SkFont font(std::move(typeface), SkIntToScalar(params.font_desc.size)); + font.setHinting(SkFontHinting::kFull); if (params.allow_subpixel_aa) { - paint.setSubpixelText(true); - paint.setLCDRenderText(true); + font.setSubpixel(true); + font.setEdging(SkFont::Edging::kSubpixelAntiAlias); } SkScalar x = SkIntToScalar(params.position.x); @@ -315,15 +314,16 @@ int32_t PepperFlashRendererHostQt::OnDrawGlyphs( // Build up the skia advances. size_t glyph_count = params.glyph_indices.size(); if (glyph_count) { - std::vector<SkPoint> sk_positions(glyph_count); + SkTextBlobBuilder builder; + auto rec = builder.allocRunPos(font, glyph_count); + memcpy(rec.glyphs, ¶ms.glyph_indices[0], glyph_count * 2); + SkPoint* pos = reinterpret_cast<SkPoint*>(rec.pos); for (uint32_t i = 0; i < glyph_count; i++) { - sk_positions[i].set(x, y); + pos[i].set(x, y); x += SkFloatToScalar(params.glyph_advances[i].x); y += SkFloatToScalar(params.glyph_advances[i].y); } - - canvas->drawPosText( - ¶ms.glyph_indices[0], glyph_count * 2, &sk_positions[0], paint); + canvas->drawTextBlob(builder.make(), 0, 0, paint); } if (needs_unmapping) @@ -351,7 +351,7 @@ int32_t PepperFlashRendererHostQt::OnNavigate( std::map<std::string, FlashNavigateUsage>& rejected_headers = g_rejected_headers.Get(); if (rejected_headers.empty()) { - for (size_t i = 0; i < arraysize(kRejectedHttpRequestHeaders); ++i) + for (size_t i = 0; i < base::size(kRejectedHttpRequestHeaders); ++i) rejected_headers[kRejectedHttpRequestHeaders[i]] = static_cast<FlashNavigateUsage>(i); } diff --git a/src/core/renderer/pepper/pepper_renderer_host_factory_qt.cpp b/src/core/renderer/pepper/pepper_renderer_host_factory_qt.cpp index 4acf69043..33c744f13 100644 --- a/src/core/renderer/pepper/pepper_renderer_host_factory_qt.cpp +++ b/src/core/renderer/pepper/pepper_renderer_host_factory_qt.cpp @@ -44,9 +44,13 @@ #include "pepper_renderer_host_factory_qt.h" #include "pepper_flash_renderer_host_qt.h" +#include "qtwebenginecoreglobal_p.h" #include "base/memory/ptr_util.h" #include "chrome/renderer/pepper/pepper_flash_font_file_host.h" +#if QT_CONFIG(webengine_printing_and_pdf) +#include "components/pdf/renderer/pepper_pdf_host.h" +#endif // QT_CONFIG(webengine_printing_and_pdf) #include "content/public/renderer/renderer_ppapi_host.h" #include "ppapi/host/ppapi_host.h" #include "ppapi/host/resource_host.h" @@ -100,7 +104,7 @@ std::unique_ptr<ppapi::host::ResourceHost> PepperRendererHostFactoryQt::CreateRe // We should either rename PPB_FlashFont_File to PPB_FontFile_Private or get // rid of its use in PDF if possible. if (host_->GetPpapiHost()->permissions().HasPermission(ppapi::PERMISSION_FLASH) - || host_->GetPpapiHost()->permissions().HasPermission(ppapi::PERMISSION_PRIVATE)) { + || host_->GetPpapiHost()->permissions().HasPermission(ppapi::PERMISSION_PDF)) { switch (message.type()) { case PpapiHostMsg_FlashFontFile_Create::ID: { ppapi::proxy::SerializedFontDescription description; @@ -115,14 +119,14 @@ std::unique_ptr<ppapi::host::ResourceHost> PepperRendererHostFactoryQt::CreateRe } } - if (host_->GetPpapiHost()->permissions().HasPermission(ppapi::PERMISSION_PRIVATE)) { +#if QT_CONFIG(webengine_printing_and_pdf) + if (host_->GetPpapiHost()->permissions().HasPermission(ppapi::PERMISSION_PDF)) { switch (message.type()) { case PpapiHostMsg_PDF_Create::ID: - // Not implemented - break; + return std::make_unique<pdf::PepperPDFHost>(host_, instance, resource); } } - +#endif // QT_CONFIG(webengine_printing_and_pdf) return nullptr; } diff --git a/src/core/renderer/print_web_view_helper_delegate_qt.cpp b/src/core/renderer/print_web_view_helper_delegate_qt.cpp index e693cf096..67cdd6b66 100644 --- a/src/core/renderer/print_web_view_helper_delegate_qt.cpp +++ b/src/core/renderer/print_web_view_helper_delegate_qt.cpp @@ -41,8 +41,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE.Chromium file. -#include "print_web_view_helper_delegate_qt.h" +#include "content/public/renderer/render_frame.h" +#include "content/public/renderer/render_view.h" +#include "extensions/common/constants.h" +#include "third_party/blink/public/web/web_document.h" #include "third_party/blink/public/web/web_element.h" +#include "third_party/blink/public/web/web_local_frame.h" + +#include "print_web_view_helper_delegate_qt.h" #include "web_engine_library_info.h" namespace QtWebEngineCore { @@ -58,6 +64,15 @@ bool PrintWebViewHelperDelegateQt::CancelPrerender(content::RenderFrame *) blink::WebElement PrintWebViewHelperDelegateQt::GetPdfElement(blink::WebLocalFrame* frame) { + GURL url = frame->GetDocument().Url(); + if (url.SchemeIs(extensions::kExtensionScheme) && url.host() == extension_misc::kPdfExtensionId) + { + // <object> with id="plugin" is created in + // chrome/browser/resources/pdf/pdf.js. + auto plugin_element = frame->GetDocument().GetElementById("plugin"); + CHECK(!plugin_element.IsNull()); + return plugin_element; + } return blink::WebElement(); } diff --git a/src/core/renderer/render_frame_observer_qt.h b/src/core/renderer/render_frame_observer_qt.h index bca45bd8e..4c05422bb 100644 --- a/src/core/renderer/render_frame_observer_qt.h +++ b/src/core/renderer/render_frame_observer_qt.h @@ -44,6 +44,8 @@ #include "base/compiler_specific.h" #include "content/public/renderer/render_frame_observer.h" #include "content/public/renderer/render_frame_observer_tracker.h" +#include "ppapi/buildflags/buildflags.h" +#include "services/service_manager/public/cpp/binder_registry.h" namespace content { class RenderFrame; @@ -67,10 +69,13 @@ public: bool isFrameDetached() const; + service_manager::BinderRegistry* registry() { return ®istry_; } + private: DISALLOW_COPY_AND_ASSIGN(RenderFrameObserverQt); bool m_isFrameDetached; + service_manager::BinderRegistry registry_; }; } // namespace QtWebEngineCore diff --git a/src/core/renderer/render_thread_observer_qt.cpp b/src/core/renderer/render_thread_observer_qt.cpp new file mode 100644 index 000000000..64b9fd961 --- /dev/null +++ b/src/core/renderer/render_thread_observer_qt.cpp @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// based on chrome/renderer/chrome_render_thread_observer.cc: +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "renderer/render_thread_observer_qt.h" + +#include "third_party/blink/public/common/associated_interfaces/associated_interface_registry.h" + +namespace QtWebEngineCore { + +bool RenderThreadObserverQt::m_isIncognitoProcess = false; + +void RenderThreadObserverQt::RegisterMojoInterfaces(blink::AssociatedInterfaceRegistry *associated_interfaces) +{ + associated_interfaces->AddInterface(base::Bind(&RenderThreadObserverQt::OnRendererConfigurationAssociatedRequest, base::Unretained(this))); +} + +void RenderThreadObserverQt::UnregisterMojoInterfaces(blink::AssociatedInterfaceRegistry *associated_interfaces) +{ + associated_interfaces->RemoveInterface(qtwebengine::mojom::RendererConfiguration::Name_); +} + +void RenderThreadObserverQt::SetInitialConfiguration(bool is_incognito_process) +{ + m_isIncognitoProcess = is_incognito_process; +} + +void RenderThreadObserverQt::OnRendererConfigurationAssociatedRequest(qtwebengine::mojom::RendererConfigurationAssociatedRequest request) +{ + m_rendererConfigurationBindings.AddBinding(this, std::move(request)); +} + +} // namespace diff --git a/src/core/renderer/render_thread_observer_qt.h b/src/core/renderer/render_thread_observer_qt.h new file mode 100644 index 000000000..29b842ab4 --- /dev/null +++ b/src/core/renderer/render_thread_observer_qt.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef RENDER_THREAD_OBSERVER_QT_H +#define RENDER_THREAD_OBSERVER_QT_H + +#include "content/public/renderer/render_thread_observer.h" +#include "mojo/public/cpp/bindings/associated_binding_set.h" +#include "qtwebengine/common/renderer_configuration.mojom.h" + +namespace QtWebEngineCore { + +class RenderThreadObserverQt : public content::RenderThreadObserver, + public qtwebengine::mojom::RendererConfiguration { +public: + + RenderThreadObserverQt() = default; + ~RenderThreadObserverQt() override = default; + + static bool is_incognito_process() { return m_isIncognitoProcess; } + +private: + // content::RenderThreadObserver: + void RegisterMojoInterfaces(blink::AssociatedInterfaceRegistry *associated_interfaces) override; + void UnregisterMojoInterfaces(blink::AssociatedInterfaceRegistry *associated_interfaces) override; + + // qtwebengine::mojom::RendererConfiguration: + void SetInitialConfiguration(bool is_incognito_process) override; + + void OnRendererConfigurationAssociatedRequest(qtwebengine::mojom::RendererConfigurationAssociatedRequest request); + + static bool m_isIncognitoProcess; + + mojo::AssociatedBindingSet<qtwebengine::mojom::RendererConfiguration> m_rendererConfigurationBindings; + + DISALLOW_COPY_AND_ASSIGN(RenderThreadObserverQt); +}; + +} // namespace QtWebEngineCore + +#endif // RENDER_THREAD_OBSERVER_QT_H diff --git a/src/core/renderer/render_view_observer_qt.cpp b/src/core/renderer/render_view_observer_qt.cpp index d37b67ebc..2795de4b9 100644 --- a/src/core/renderer/render_view_observer_qt.cpp +++ b/src/core/renderer/render_view_observer_qt.cpp @@ -80,7 +80,7 @@ void RenderViewObserverQt::onFetchDocumentInnerText(quint64 requestId) void RenderViewObserverQt::onSetBackgroundColor(quint32 color) { - render_view()->GetWebFrameWidget()->SetBaseBackgroundColor(color); + render_view()->GetWebView()->SetBaseBackgroundColor(color); } void RenderViewObserverQt::OnDestruct() diff --git a/src/core/renderer/user_resource_controller.cpp b/src/core/renderer/user_resource_controller.cpp index 9c03cd651..be5e6f043 100644 --- a/src/core/renderer/user_resource_controller.cpp +++ b/src/core/renderer/user_resource_controller.cpp @@ -103,7 +103,7 @@ static bool scriptMatchesURL(const UserScriptData &scriptData, const GURL &url) matchFound = false; for (auto it = scriptData.urlPatterns.begin(), end = scriptData.urlPatterns.end(); it != end; ++it) { URLPattern urlPattern(validUserScriptSchemes()); - if (urlPattern.Parse(*it) == URLPattern::PARSE_SUCCESS && urlPattern.MatchesURL(url)) + if (urlPattern.Parse(*it) == URLPattern::ParseResult::kSuccess && urlPattern.MatchesURL(url)) matchFound = true; } if (!matchFound) @@ -137,7 +137,7 @@ public: private: // RenderFrameObserver implementation. - void DidCommitProvisionalLoad(bool is_new_navigation, bool is_same_document_navigation) override; + void DidCommitProvisionalLoad(bool is_same_document_navigation, ui::PageTransition transition) override; void DidFinishDocumentLoad() override; void DidFinishLoad() override; void FrameDetached() override; @@ -229,8 +229,8 @@ UserResourceController::RenderViewObserverHelper::RenderViewObserverHelper(conte { } -void UserResourceController::RenderFrameObserverHelper::DidCommitProvisionalLoad(bool /* is_new_navigation */, - bool is_same_document_navigation) +void UserResourceController::RenderFrameObserverHelper::DidCommitProvisionalLoad(bool is_same_document_navigation, + ui::PageTransition /*transitionbool*/) { if (is_same_document_navigation) return; diff --git a/src/core/renderer/web_channel_ipc_transport.cpp b/src/core/renderer/web_channel_ipc_transport.cpp index 1f496e810..3b9c17b6a 100644 --- a/src/core/renderer/web_channel_ipc_transport.cpp +++ b/src/core/renderer/web_channel_ipc_transport.cpp @@ -119,7 +119,9 @@ void WebChannelTransport::Uninstall(blink::WebLocalFrame *frame, uint worldId) if (qtObjectValue.IsEmpty() || !qtObjectValue->IsObject()) return; v8::Local<v8::Object> qtObject = v8::Local<v8::Object>::Cast(qtObjectValue); - qtObject->Delete(gin::StringToV8(isolate, "webChannelTransport")); + // FIXME: ? + auto whocares = qtObject->Delete(context, gin::StringToV8(isolate, "webChannelTransport")); + Q_UNUSED(whocares); } void WebChannelTransport::NativeQtSendMessage(gin::Arguments *args) @@ -137,6 +139,8 @@ void WebChannelTransport::NativeQtSendMessage(gin::Arguments *args) args->ThrowTypeError("Missing argument"); return; } + v8::Isolate *isolate = blink::MainThreadIsolate(); + v8::HandleScope handleScope(isolate); if (!jsonValue->IsString()) { args->ThrowTypeError("Expected string"); @@ -144,10 +148,10 @@ void WebChannelTransport::NativeQtSendMessage(gin::Arguments *args) } v8::Local<v8::String> jsonString = v8::Local<v8::String>::Cast(jsonValue); - QByteArray json(jsonString->Utf8Length(), 0); - jsonString->WriteUtf8(json.data(), json.size(), - nullptr, - v8::String::REPLACE_INVALID_UTF8); + QByteArray json(jsonString->Utf8Length(isolate), 0); + jsonString->WriteUtf8(isolate, + json.data(), json.size(), + nullptr, v8::String::REPLACE_INVALID_UTF8); QJsonParseError error; QJsonDocument doc = QJsonDocument::fromJson(json, &error); diff --git a/src/core/renderer_host/pepper/pepper_isolated_file_system_message_filter.cpp b/src/core/renderer_host/pepper/pepper_isolated_file_system_message_filter.cpp index 2c8b1246a..5d7c3973f 100644 --- a/src/core/renderer_host/pepper/pepper_isolated_file_system_message_filter.cpp +++ b/src/core/renderer_host/pepper/pepper_isolated_file_system_message_filter.cpp @@ -45,8 +45,10 @@ #include "pepper_isolated_file_system_message_filter.h" #include "base/macros.h" +#include "base/task/post_task.h" #include "chrome/common/chrome_switches.h" #include "content/public/browser/browser_ppapi_host.h" +#include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/child_process_security_policy.h" #include "content/public/browser/render_view_host.h" @@ -83,7 +85,7 @@ scoped_refptr<base::TaskRunner> PepperIsolatedFileSystemMessageFilter::OverrideT { // In order to reach ExtensionSystem, we need to get ProfileManager first. // ProfileManager lives in UI thread, so we need to do this in UI thread. - return content::BrowserThread::GetTaskRunnerForThread(content::BrowserThread::UI); + return base::CreateSingleThreadTaskRunnerWithTraits({content::BrowserThread::UI}); } int32_t PepperIsolatedFileSystemMessageFilter::OnResourceMessageReceived(const IPC::Message& msg, ppapi::host::HostMessageContext *context) diff --git a/src/core/render_view_observer_host_qt.cpp b/src/core/renderer_host/render_view_observer_host_qt.cpp index c097e102d..c097e102d 100644 --- a/src/core/render_view_observer_host_qt.cpp +++ b/src/core/renderer_host/render_view_observer_host_qt.cpp diff --git a/src/core/render_view_observer_host_qt.h b/src/core/renderer_host/render_view_observer_host_qt.h index a08263e07..a08263e07 100644 --- a/src/core/render_view_observer_host_qt.h +++ b/src/core/renderer_host/render_view_observer_host_qt.h diff --git a/src/core/renderer_host/resource_dispatcher_host_delegate_qt.cpp b/src/core/renderer_host/resource_dispatcher_host_delegate_qt.cpp new file mode 100644 index 000000000..36c5e6ed1 --- /dev/null +++ b/src/core/renderer_host/resource_dispatcher_host_delegate_qt.cpp @@ -0,0 +1,186 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE.Chromium file. + +#include "resource_dispatcher_host_delegate_qt.h" + +#include "base/bind.h" +#include "base/guid.h" +#include "base/strings/stringprintf.h" +#include "base/task/post_task.h" +#include "content/public/browser/browser_context.h" +#include "content/public/browser/browser_task_traits.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/download_manager.h" +#include "content/public/browser/download_request_utils.h" +#include "content/public/browser/navigation_controller.h" + +#include "content/public/browser/render_frame_host.h" +#include "content/public/browser/render_view_host.h" +#include "content/public/browser/resource_dispatcher_host.h" +#include "content/public/browser/resource_request_info.h" +#include "content/public/browser/stream_info.h" +#include "content/public/browser/web_contents.h" + +#include "extensions/extension_system_qt.h" +#include "extensions/browser/info_map.h" +#include "extensions/common/constants.h" +#include "extensions/common/extension.h" +#include "extensions/common/manifest_handlers/mime_types_handler.h" + +#include "net/base/escape.h" +#include "net/url_request/url_request.h" + +#include "profile_io_data_qt.h" +#include "type_conversion.h" +#include "web_contents_delegate_qt.h" +#include "web_engine_settings.h" + +namespace QtWebEngineCore { + +void OnPdfStreamIntercepted( + const GURL& original_url, + std::string extension_id, + int frame_tree_node_id, + const content::ResourceRequestInfo::WebContentsGetter& + web_contents_getter) { + content::WebContents* web_contents = web_contents_getter.Run(); + if (!web_contents) + return; + + WebContentsDelegateQt *contentsDelegate = static_cast<WebContentsDelegateQt*>(web_contents->GetDelegate()); + if (!contentsDelegate) + return; + + WebEngineSettings *settings = contentsDelegate->webEngineSettings(); + if (!settings->testAttribute(WebEngineSettings::PdfViewerEnabled) + || !settings->testAttribute(WebEngineSettings::PluginsEnabled)) { + // If the applications has been set up to always download PDF files to open them in an + // external viewer, trigger the download. + std::unique_ptr<download::DownloadUrlParameters> params( + content::DownloadRequestUtils::CreateDownloadForWebContentsMainFrame( + web_contents, original_url, NO_TRAFFIC_ANNOTATION_YET)); + content::BrowserContext::GetDownloadManager(web_contents->GetBrowserContext()) + ->DownloadUrl(std::move(params)); + return; + } + + // The URL passes the original pdf resource url, that will be requested + // by the pdf viewer extension page. + content::NavigationController::LoadURLParams params( + GURL(base::StringPrintf("%s://%s/index.html?%s", extensions::kExtensionScheme, + extension_id.c_str(), + original_url.spec().c_str()))); + + params.frame_tree_node_id = frame_tree_node_id; + web_contents->GetController().LoadURLWithParams(params); +} + +bool ResourceDispatcherHostDelegateQt::ShouldInterceptResourceAsStream(net::URLRequest *request, + const std::string &mime_type, + GURL *origin, + std::string *payload) +{ + const content::ResourceRequestInfo* info = + content::ResourceRequestInfo::ForRequest(request); + + int render_process_host_id = -1; + int render_frame_id = -1; + if (!content::ResourceRequestInfo::GetRenderFrameForRequest(request, &render_process_host_id, &render_frame_id)) + return false; + + std::vector<std::string> whitelist = MimeTypesHandler::GetMIMETypeWhitelist(); + + extensions::ExtensionSystemQt *extensionSystem = ProfileIODataQt::FromResourceContext(info->GetContext())->GetExtensionSystem(); + if (!extensionSystem) + return false; + + const scoped_refptr<const extensions::InfoMap> extension_info_map(extensionSystem->info_map()); + + for (const std::string &extension_id : whitelist) { + const extensions::Extension *extension = extension_info_map->extensions().GetByID(extension_id); + if (!extension) + continue; + + MimeTypesHandler* handler = MimeTypesHandler::GetHandler(extension); + if (!handler) + continue; + if (handler->CanHandleMIMEType(mime_type)) { + StreamTargetInfo target_info; + *origin = extensions::Extension::GetBaseURLFromExtensionId(extension_id); + target_info.extension_id = extension_id; + target_info.view_id = base::GenerateGUID(); + *payload = target_info.view_id; + stream_target_info_[request] = target_info; + return true; + } + } + return false; +} + +// Informs the delegate that a Stream was created. The Stream can be read from +// the blob URL of the Stream, but can only be read once. +void ResourceDispatcherHostDelegateQt::OnStreamCreated(net::URLRequest *request, + std::unique_ptr<content::StreamInfo> stream) +{ + const content::ResourceRequestInfo *info = content::ResourceRequestInfo::ForRequest(request); + std::map<net::URLRequest *, StreamTargetInfo>::iterator ix = stream_target_info_.find(request); + CHECK(ix != stream_target_info_.end()); + int render_frame_id = -1; + int render_process_id = -1; + if (!content::ResourceRequestInfo::GetRenderFrameForRequest(request, &render_process_id, &render_frame_id)) { + stream_target_info_.erase(request); + request->Cancel(); + return; + } + + base::PostTaskWithTraits( + FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(&OnPdfStreamIntercepted, + request->url(), ix->second.extension_id, + info->GetFrameTreeNodeId(), info->GetWebContentsGetterForRequest() + ) + ); + stream_target_info_.erase(request); +} + +} // namespace QtWebEngineCore diff --git a/src/core/renderer_host/resource_dispatcher_host_delegate_qt.h b/src/core/renderer_host/resource_dispatcher_host_delegate_qt.h new file mode 100644 index 000000000..3039fd03e --- /dev/null +++ b/src/core/renderer_host/resource_dispatcher_host_delegate_qt.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef RESOURCE_DISPATCHER_HOST_DELEGATE_QT_H +#define RESOURCE_DISPATCHER_HOST_DELEGATE_QT_H + +#include "content/public/browser/resource_dispatcher_host_delegate.h" +#include "extensions/buildflags/buildflags.h" + +#include "web_contents_adapter_client.h" + +namespace QtWebEngineCore { + +class ResourceDispatcherHostDelegateQt : public content::ResourceDispatcherHostDelegate { +public: + // If the stream will be rendered in a BrowserPlugin, |payload| will contain + // the data that should be given to the old ResourceHandler to forward to the + // renderer process. + bool ShouldInterceptResourceAsStream(net::URLRequest *request, + const std::string &mime_type, + GURL *origin, + std::string *payload) override; + + // Informs the delegate that a Stream was created. The Stream can be read from + // the blob URL of the Stream, but can only be read once. + void OnStreamCreated(net::URLRequest *request, + std::unique_ptr<content::StreamInfo> stream) override; +private: +#if BUILDFLAG(ENABLE_EXTENSIONS) + struct StreamTargetInfo { + std::string extension_id; + std::string view_id; + }; + std::map<net::URLRequest *, StreamTargetInfo> stream_target_info_; +#endif + +}; + +} // namespace QtWebEngineCore + +#endif // RESOURCE_DISPATCHER_HOST_DELEGATE_QT_H diff --git a/src/core/renderer_host/user_resource_controller_host.h b/src/core/renderer_host/user_resource_controller_host.h index 40b685163..16a73f5fb 100644 --- a/src/core/renderer_host/user_resource_controller_host.h +++ b/src/core/renderer_host/user_resource_controller_host.h @@ -66,7 +66,7 @@ namespace QtWebEngineCore { class WebContentsAdapter; -class QWEBENGINECORE_PRIVATE_EXPORT UserResourceControllerHost { +class Q_WEBENGINECORE_PRIVATE_EXPORT UserResourceControllerHost { public: UserResourceControllerHost(); diff --git a/src/core/resource_bundle_qt.cpp b/src/core/resource_bundle_qt.cpp index 428faa34e..dc7507f34 100644 --- a/src/core/resource_bundle_qt.cpp +++ b/src/core/resource_bundle_qt.cpp @@ -71,6 +71,7 @@ gfx::Image& ResourceBundle::GetNativeImageNamed(int resource_id) return GetEmptyImage(); } +// static bool ResourceBundle::LocaleDataPakExists(const std::string& locale) { #if defined(OS_LINUX) diff --git a/src/core/resource_context_qt.cpp b/src/core/resource_context_qt.cpp index 6dfa5064e..79c105956 100644 --- a/src/core/resource_context_qt.cpp +++ b/src/core/resource_context_qt.cpp @@ -39,15 +39,6 @@ #include "resource_context_qt.h" -#include "content/public/browser/browser_thread.h" -#include "content/public/browser/storage_partition.h" -#include "net/dns/host_resolver.h" -#include "net/url_request/url_request_context.h" -#include "net/url_request/url_request_context_getter.h" -#include "profile_io_data_qt.h" - -#include <qglobal.h> - namespace QtWebEngineCore { ResourceContextQt::ResourceContextQt(ProfileIODataQt *io_data) @@ -55,13 +46,4 @@ ResourceContextQt::ResourceContextQt(ProfileIODataQt *io_data) { } -net::URLRequestContext* ResourceContextQt::GetRequestContext() -{ - Q_ASSERT(m_io_data); - DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - // FIXME: This is the only remaining use of GetRequestContext(), - // but we are on the wrong thread for calling BrowserContext::GetDefaultStoragePartition - return m_io_data->urlRequestContext(); -} - } // namespace QtWebEngineCore diff --git a/src/core/resource_context_qt.h b/src/core/resource_context_qt.h index 6a5e7a74e..4107e7c24 100644 --- a/src/core/resource_context_qt.h +++ b/src/core/resource_context_qt.h @@ -42,6 +42,21 @@ #include "content/public/browser/resource_context.h" +#include "extensions/buildflags/buildflags.h" + +namespace net { +class URLRequestContext; +class URLRequestContextGetter; +} + +#if BUILDFLAG(ENABLE_EXTENSIONS) +namespace extensions { +class ExtensionSystemQt; +} +#endif // BUILDFLAG(ENABLE_EXTENSIONS) + +class GURL; + namespace QtWebEngineCore { class ProfileIODataQt; @@ -50,8 +65,8 @@ class ResourceContextQt : public content::ResourceContext { public: ResourceContextQt(ProfileIODataQt *io_data); - net::URLRequestContext *GetRequestContext() override; private: + friend class ProfileIODataQt; ProfileIODataQt* m_io_data; DISALLOW_COPY_AND_ASSIGN(ResourceContextQt); }; diff --git a/src/core/service/service_qt.cpp b/src/core/service/service_qt.cpp index 30ed269e8..83948e396 100644 --- a/src/core/service/service_qt.cpp +++ b/src/core/service/service_qt.cpp @@ -45,13 +45,15 @@ #include "service_qt.h" #include "base/no_destructor.h" +#include "base/task/post_task.h" #include "components/spellcheck/spellcheck_buildflags.h" +#include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/content_browser_client.h" #include "services/service_manager/public/cpp/binder_registry.h" #include "services/service_manager/public/cpp/connector.h" #include "services/service_manager/public/cpp/service.h" -#include "services/service_manager/public/cpp/service_context.h" +#include "services/service_manager/public/cpp/service_binding.h" #if BUILDFLAG(ENABLE_SPELLCHECK) #include "chrome/browser/spellchecker/spell_check_host_chrome_impl.h" @@ -62,6 +64,7 @@ public: IOThreadContext(); ~IOThreadContext() override = default; + void BindServiceRequest(service_manager::mojom::ServiceRequest request); void BindConnector(service_manager::mojom::ConnectorRequest connector_request); private: @@ -74,6 +77,7 @@ private: mojo::ScopedMessagePipeHandle handle) override; service_manager::mojom::ConnectorRequest m_connectorRequest; + service_manager::ServiceBinding m_serviceBinding{this}; service_manager::BinderRegistry m_registry; service_manager::BinderRegistryWithArgs<const service_manager::BindSourceInfo&> m_registry_with_source_info; @@ -82,13 +86,18 @@ private: ServiceQt::IOThreadContext::IOThreadContext() { - scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner = - content::BrowserThread::GetTaskRunnerForThread(content::BrowserThread::UI); #if BUILDFLAG(ENABLE_SPELLCHECK) - m_registry_with_source_info.AddInterface(base::Bind(&SpellCheckHostChromeImpl::Create), ui_task_runner); + scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner = + base::CreateSingleThreadTaskRunnerWithTraits({content::BrowserThread::UI}); + m_registry_with_source_info.AddInterface(base::BindRepeating(&SpellCheckHostChromeImpl::Create), ui_task_runner); #endif } +void ServiceQt::IOThreadContext::BindServiceRequest(service_manager::mojom::ServiceRequest request) +{ + m_serviceBinding.Bind(std::move(request)); +} + void ServiceQt::IOThreadContext::BindConnector(service_manager::mojom::ConnectorRequest connector_request) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); @@ -97,7 +106,7 @@ void ServiceQt::IOThreadContext::BindConnector(service_manager::mojom::Connector // on the IO thread. Post a task instead. As long as this task is posted // before any code attempts to connect to the chrome service, there's no // race. - content::BrowserThread::GetTaskRunnerForThread(content::BrowserThread::IO)->PostTask( + base::CreateSingleThreadTaskRunnerWithTraits({content::BrowserThread::IO})->PostTask( FROM_HERE, base::BindOnce(&IOThreadContext::BindConnectorOnIOThread, base::Unretained(this), @@ -114,7 +123,7 @@ void ServiceQt::IOThreadContext::OnStart() { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); DCHECK(m_connectorRequest.is_pending()); - context()->connector()->BindConnectorRequest(std::move(m_connectorRequest)); + m_serviceBinding.GetConnector()->BindConnectorRequest(std::move(m_connectorRequest)); } void ServiceQt::IOThreadContext::OnBindInterface(const service_manager::BindSourceInfo &remote_info, @@ -136,9 +145,9 @@ ServiceQt *ServiceQt::GetInstance() return service.get(); } -service_manager::EmbeddedServiceInfo::ServiceFactory ServiceQt::CreateServiceQtFactory() +content::ServiceManagerConnection::ServiceRequestHandler ServiceQt::CreateServiceQtRequestHandler() { - return base::BindRepeating(&ServiceQt::CreateServiceQtWrapper, base::Unretained(this)); + return base::BindRepeating(&ServiceQt::BindServiceQtRequest, base::Unretained(this)); } ServiceQt::ServiceQt() : m_ioThreadContext(std::make_unique<IOThreadContext>()) @@ -153,8 +162,8 @@ void ServiceQt::InitConnector() m_ioThreadContext->BindConnector(std::move(request)); } -std::unique_ptr<service_manager::Service> ServiceQt::CreateServiceQtWrapper() +void ServiceQt::BindServiceQtRequest(service_manager::mojom::ServiceRequest request) { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - return std::make_unique<service_manager::ForwardingService>(m_ioThreadContext.get()); + m_ioThreadContext->BindServiceRequest(std::move(request)); } diff --git a/src/core/service/service_qt.h b/src/core/service/service_qt.h index 4aa0a3996..d4c89065c 100644 --- a/src/core/service/service_qt.h +++ b/src/core/service/service_qt.h @@ -41,7 +41,7 @@ #define SERVICE_QT_H #include "base/no_destructor.h" -#include "services/service_manager/embedder/embedded_service_info.h" +#include "content/public/common/service_manager_connection.h" namespace service_manager { class Connector; @@ -53,7 +53,7 @@ public: static ServiceQt *GetInstance(); void InitConnector(); - service_manager::EmbeddedServiceInfo::ServiceFactory CreateServiceQtFactory(); + content::ServiceManagerConnection::ServiceRequestHandler CreateServiceQtRequestHandler(); service_manager::Connector *connector() { return m_connector.get(); } private: @@ -63,7 +63,7 @@ private: ServiceQt(); ~ServiceQt(); - std::unique_ptr<service_manager::Service> CreateServiceQtWrapper(); + void BindServiceQtRequest(service_manager::mojom::ServiceRequest request); const std::unique_ptr<IOThreadContext> m_ioThreadContext; diff --git a/src/core/touch_handle_drawable_client.h b/src/core/touch_handle_drawable_client.h new file mode 100644 index 000000000..a2c87948a --- /dev/null +++ b/src/core/touch_handle_drawable_client.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TOUCH_HANDLE_DRAWABLE_CLIENT_H +#define TOUCH_HANDLE_DRAWABLE_CLIENT_H + +#include "qtwebenginecoreglobal_p.h" +#include <QRect> + +namespace QtWebEngineCore { + +class Q_WEBENGINECORE_PRIVATE_EXPORT TouchHandleDrawableClient { +public: + virtual ~TouchHandleDrawableClient() { } + + virtual void setImage(int orientation) = 0; + virtual void setBounds(const QRect &bounds) = 0; + virtual void setVisible(bool visible) = 0; + virtual void setOpacity(float opacity) = 0; +}; + +} // namespace QtWebEngineCore + +#endif // TOUCH_HANDLE_DRAWABLE_CLIENT_H diff --git a/src/core/touch_handle_drawable_qt.cpp b/src/core/touch_handle_drawable_qt.cpp new file mode 100644 index 000000000..66b1cf40e --- /dev/null +++ b/src/core/touch_handle_drawable_qt.cpp @@ -0,0 +1,211 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE.Chromium file. + +// This implementation is based on chromium/ui/touch_selection/touch_handle_drawable_aura.cc + +#include "render_widget_host_view_qt.h" +#include "touch_handle_drawable_client.h" +#include "touch_handle_drawable_qt.h" +#include "type_conversion.h" +#include "web_contents_adapter_client.h" + +#include "ui/gfx/image/image.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/resources/grit/ui_resources.h" + +namespace QtWebEngineCore { + +namespace { +// The distance by which a handle image is offset from the focal point (i.e. +// text baseline) downwards. +const int kSelectionHandleVerticalVisualOffset = 2; + +// The padding around the selection handle image can be used to extend the +// handle window so that touch events near the selection handle image are +// targeted to the selection handle window. +const int kSelectionHandlePadding = 0; + +// Epsilon value used to compare float values to zero. +const float kEpsilon = 1e-8f; + +// Returns the appropriate handle image based on the handle orientation. +gfx::Image* GetHandleImage(ui::TouchHandleOrientation orientation) +{ + int resource_id = 0; + switch (orientation) { + case ui::TouchHandleOrientation::LEFT: + resource_id = IDR_TEXT_SELECTION_HANDLE_LEFT; + break; + case ui::TouchHandleOrientation::CENTER: + resource_id = IDR_TEXT_SELECTION_HANDLE_CENTER; + break; + case ui::TouchHandleOrientation::RIGHT: + resource_id = IDR_TEXT_SELECTION_HANDLE_RIGHT; + break; + case ui::TouchHandleOrientation::UNDEFINED: + NOTREACHED() << "Invalid touch handle bound type."; + return nullptr; + }; + return &ui::ResourceBundle::GetSharedInstance().GetImageNamed(resource_id); +} + +bool IsNearlyZero(float value) +{ + return std::abs(value) < kEpsilon; +} + +} // namespace + +TouchHandleDrawableQt::TouchHandleDrawableQt(RenderWidgetHostViewQt *rwhv) + : m_rwhv(rwhv) + , m_enabled(false) + , m_alpha(0) + , m_orientation(ui::TouchHandleOrientation::UNDEFINED) +{ + QMap<int, QImage> images; + for (int orientation = 0; orientation < static_cast<int>(ui::TouchHandleOrientation::UNDEFINED); ++orientation) { + gfx::Image* image = GetHandleImage(static_cast<ui::TouchHandleOrientation>(orientation)); + images.insert(orientation, toQImage(image->AsBitmap())); + } + + Q_ASSERT(m_rwhv); + Q_ASSERT(m_rwhv->adapterClient()); + m_client.reset(m_rwhv->adapterClient()->createTouchHandle(images)); +} + +TouchHandleDrawableQt::~TouchHandleDrawableQt() +{ +} + +void TouchHandleDrawableQt::UpdateBounds() +{ + if (!m_client) + return; + + gfx::RectF newBounds = m_relativeBounds; + newBounds.Offset(m_originPosition.x(), m_originPosition.y()); + m_client->setBounds(toQt(gfx::ToEnclosingRect(newBounds))); +} + +bool TouchHandleDrawableQt::IsVisible() const +{ + return m_enabled && !IsNearlyZero(m_alpha); +} + +void TouchHandleDrawableQt::SetEnabled(bool enabled) +{ + if (!m_client) + return; + + if (enabled == m_enabled) + return; + + m_enabled = enabled; + m_client->setVisible(enabled); +} + +void TouchHandleDrawableQt::SetOrientation(ui::TouchHandleOrientation orientation, bool mirror_vertical, bool mirror_horizontal) +{ + if (!m_client) + return; + + // TODO: Implement adaptive handle orientation logic + DCHECK(!mirror_vertical); + DCHECK(!mirror_horizontal); + + if (m_orientation == orientation) + return; + m_orientation = orientation; + gfx::Image* image = GetHandleImage(orientation); + m_client->setImage(static_cast<int>(orientation)); + + // Calculate the relative bounds. + gfx::Size image_size = image->Size(); + int window_width = image_size.width() + 2 * kSelectionHandlePadding; + int window_height = image_size.height() + 2 * kSelectionHandlePadding; + m_relativeBounds = + gfx::RectF(-kSelectionHandlePadding, + kSelectionHandleVerticalVisualOffset - kSelectionHandlePadding, + window_width, window_height); + UpdateBounds(); +} + +void TouchHandleDrawableQt::SetOrigin(const gfx::PointF& position) +{ + m_originPosition = position; + UpdateBounds(); +} + +void TouchHandleDrawableQt::SetAlpha(float alpha) +{ + if (!m_client) + return; + + if (alpha == m_alpha) + return; + + m_alpha = alpha; + m_client->setOpacity(m_alpha); + m_client->setVisible(IsVisible()); +} + +gfx::RectF TouchHandleDrawableQt::GetVisibleBounds() const +{ + gfx::RectF bounds = m_relativeBounds; + bounds.Offset(m_originPosition.x(), m_originPosition.y()); + + gfx::RectF visibleBounds(bounds); + visibleBounds.Inset(kSelectionHandlePadding, + kSelectionHandlePadding + kSelectionHandleVerticalVisualOffset, + kSelectionHandlePadding, + kSelectionHandlePadding); + return visibleBounds; +} + +float TouchHandleDrawableQt::GetDrawableHorizontalPaddingRatio() const +{ + // Qt does not have any transparent padding for its handle drawable. + return 0.0; +} + +} // namespace QtWebEngineCore diff --git a/src/core/touch_handle_drawable_qt.h b/src/core/touch_handle_drawable_qt.h new file mode 100644 index 000000000..46fa217b7 --- /dev/null +++ b/src/core/touch_handle_drawable_qt.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TOUCH_HANDLE_DRAWABLE_QT_H +#define TOUCH_HANDLE_DRAWABLE_QT_H + +#include "ui/touch_selection/touch_handle.h" +#include "ui/touch_selection/touch_handle_orientation.h" + +#include <QtCore/QScopedPointer> + +namespace QtWebEngineCore { + +class RenderWidgetHostViewQt; +class TouchHandleDrawableClient; + +class TouchHandleDrawableQt : public ui::TouchHandleDrawable +{ +public: + explicit TouchHandleDrawableQt(RenderWidgetHostViewQt *rwhv); + ~TouchHandleDrawableQt() override; + +private: + void UpdateBounds(); + bool IsVisible() const; + + // ui::TouchHandleDrawable overrides + void SetEnabled(bool enabled) override; + void SetOrientation(ui::TouchHandleOrientation orientation, + bool mirror_vertical, + bool mirror_horizontal) override; + void SetOrigin(const gfx::PointF& position) override; + void SetAlpha(float alpha) override; + gfx::RectF GetVisibleBounds() const override; + float GetDrawableHorizontalPaddingRatio() const override; + + RenderWidgetHostViewQt *m_rwhv; + QScopedPointer<TouchHandleDrawableClient> m_client; + + bool m_enabled; + float m_alpha; + ui::TouchHandleOrientation m_orientation; + gfx::RectF m_relativeBounds; + gfx::PointF m_originPosition; + + DISALLOW_COPY_AND_ASSIGN(TouchHandleDrawableQt); +}; + +} // namespace QtWebEngineCore + +#endif // TOUCH_HANDLE_DRAWABLE_QT_H diff --git a/src/core/touch_selection_controller_client_qt.cpp b/src/core/touch_selection_controller_client_qt.cpp new file mode 100644 index 000000000..0f44210d1 --- /dev/null +++ b/src/core/touch_selection_controller_client_qt.cpp @@ -0,0 +1,343 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "render_widget_host_view_qt.h" +#include "touch_handle_drawable_qt.h" +#include "touch_selection_controller_client_qt.h" +#include "touch_selection_menu_controller.h" +#include "type_conversion.h" +#include "web_contents_adapter.h" +#include "web_contents_adapter_client.h" + +#include "content/browser/frame_host/render_frame_host_impl.h" +#include "content/browser/renderer_host/render_widget_host_impl.h" +#include "ui/gfx/geometry/size_conversions.h" + +#include <QClipboard> +#include <QGuiApplication> + +namespace QtWebEngineCore { + +TouchSelectionControllerClientQt::TouchSelectionControllerClientQt(RenderWidgetHostViewQt *rwhv) + : m_rwhv(rwhv) + , m_menuController(new TouchSelectionMenuController(this)) + , m_menuShowing(false) + , m_menuRequested(false) + , m_touchDown(false) + , m_scrollInProgress(false) + , m_handleDragInProgress(false) +{ + Q_ASSERT(rwhv); +} + +TouchSelectionControllerClientQt::~TouchSelectionControllerClientQt() +{ +} + +bool TouchSelectionControllerClientQt::handleContextMenu(const content::ContextMenuParams& params) +{ + if ((params.source_type == ui::MENU_SOURCE_LONG_PRESS || + params.source_type == ui::MENU_SOURCE_LONG_TAP) && + params.is_editable && params.selection_text.empty()) { + m_menuRequested = true; + updateMenu(); + return true; + } + + const bool from_touch = params.source_type == ui::MENU_SOURCE_LONG_PRESS || + params.source_type == ui::MENU_SOURCE_LONG_TAP || + params.source_type == ui::MENU_SOURCE_TOUCH; + if (from_touch && !params.selection_text.empty()) + return true; + + GetTouchSelectionController()->HideAndDisallowShowingAutomatically(); + return false; +} + +void TouchSelectionControllerClientQt::onTouchDown() +{ + m_touchDown = true; + updateMenu(); +} + +void TouchSelectionControllerClientQt::onTouchUp() +{ + m_touchDown = false; + updateMenu(); +} + +void TouchSelectionControllerClientQt::onScrollBegin() +{ + m_scrollInProgress = true; + GetTouchSelectionController()->SetTemporarilyHidden(true); + updateMenu(); +} + +void TouchSelectionControllerClientQt::onScrollEnd() +{ + m_scrollInProgress = false; + GetTouchSelectionController()->SetTemporarilyHidden(false); + updateMenu(); +} + +bool TouchSelectionControllerClientQt::IsCommandIdEnabled(int command_id) const +{ + bool editable = m_rwhv->getTextInputType() != ui::TEXT_INPUT_TYPE_NONE; + bool readable = m_rwhv->getTextInputType() != ui::TEXT_INPUT_TYPE_PASSWORD; + bool hasSelection = !m_rwhv->GetSelectedText().empty(); + + switch (command_id) { + case TouchSelectionMenuController::Cut: + return editable && readable && hasSelection; + case TouchSelectionMenuController::Copy: + return readable && hasSelection; + case TouchSelectionMenuController::Paste: + return editable && !QGuiApplication::clipboard()->text().isEmpty(); + default: + return false; + } +} + +void TouchSelectionControllerClientQt::ExecuteCommand(int command_id, int event_flags) +{ + Q_UNUSED(event_flags); + GetTouchSelectionController()->HideAndDisallowShowingAutomatically(); + + WebContentsAdapterClient *adapterClient = m_rwhv->adapterClient(); + Q_ASSERT(adapterClient); + WebContentsAdapter *adapter = adapterClient->webContentsAdapter(); + Q_ASSERT(adapter); + + switch (command_id) { + case TouchSelectionMenuController::Cut: + adapter->cut(); + break; + case TouchSelectionMenuController::Copy: + adapter->copy(); + break; + case TouchSelectionMenuController::Paste: + adapter->paste(); + break; + default: + NOTREACHED(); + break; + } +} + +void TouchSelectionControllerClientQt::RunContextMenu() +{ + gfx::RectF anchorRect = GetTouchSelectionController()->GetRectBetweenBounds(); + gfx::PointF anchorPoint = gfx::PointF(anchorRect.CenterPoint().x(), anchorRect.y()); + + content::RenderWidgetHostImpl *host = m_rwhv->host(); + host->ShowContextMenuAtPoint(gfx::ToRoundedPoint(anchorPoint), + ui::MENU_SOURCE_TOUCH_EDIT_MENU); + + // Hide selection handles after getting rect-between-bounds from touch + // selection controller; otherwise, rect would be empty and the above + // calculations would be invalid. + GetTouchSelectionController()->HideAndDisallowShowingAutomatically(); +} + +void TouchSelectionControllerClientQt::DidStopFlinging() +{ + onScrollEnd(); +} + +void TouchSelectionControllerClientQt::UpdateClientSelectionBounds(const gfx::SelectionBound& start, + const gfx::SelectionBound& end) +{ + UpdateClientSelectionBounds(start, end, this, this); +} + +void TouchSelectionControllerClientQt::UpdateClientSelectionBounds(const gfx::SelectionBound& start, + const gfx::SelectionBound& end, + ui::TouchSelectionControllerClient* client, + ui::TouchSelectionMenuClient* menu_client) +{ + Q_UNUSED(client); + Q_UNUSED(menu_client); + + GetTouchSelectionController()->OnSelectionBoundsChanged(start, end); +} + +void TouchSelectionControllerClientQt::InvalidateClient(ui::TouchSelectionControllerClient* client) +{ + Q_UNUSED(client); +} + +ui::TouchSelectionController* TouchSelectionControllerClientQt::GetTouchSelectionController() +{ + return m_rwhv->getTouchSelectionController(); +} + +void TouchSelectionControllerClientQt::AddObserver(Observer* observer) +{ + Q_UNUSED(observer); +} + +void TouchSelectionControllerClientQt::RemoveObserver(Observer* observer) +{ + Q_UNUSED(observer); +} + +bool TouchSelectionControllerClientQt::SupportsAnimation() const +{ + return false; +} + +void TouchSelectionControllerClientQt::SetNeedsAnimate() +{ + NOTREACHED(); +} + +void TouchSelectionControllerClientQt::MoveCaret(const gfx::PointF& position) +{ + content::mojom::FrameInputHandler *frameInputHandler = m_rwhv->getFrameInputHandler(); + if (!frameInputHandler) + return; + + frameInputHandler->MoveCaret(gfx::ToRoundedPoint(position)); +} + +void TouchSelectionControllerClientQt::MoveRangeSelectionExtent(const gfx::PointF& extent) +{ + content::mojom::FrameInputHandler *frameInputHandler = m_rwhv->getFrameInputHandler(); + if (!frameInputHandler) + return; + + frameInputHandler->MoveRangeSelectionExtent(gfx::ToRoundedPoint(extent)); +} + +void TouchSelectionControllerClientQt::SelectBetweenCoordinates(const gfx::PointF& base, const gfx::PointF& extent) +{ + content::mojom::FrameInputHandler *frameInputHandler = m_rwhv->getFrameInputHandler(); + if (!frameInputHandler) + return; + + frameInputHandler->SelectRange(gfx::ToRoundedPoint(base), gfx::ToRoundedPoint(extent)); +} + +void TouchSelectionControllerClientQt::OnSelectionEvent(ui::SelectionEventType event) +{ + switch (event) { + case ui::SELECTION_HANDLES_SHOWN: + m_menuRequested = true; + break; + case ui::INSERTION_HANDLE_SHOWN: + break; + case ui::SELECTION_HANDLES_CLEARED: + case ui::INSERTION_HANDLE_CLEARED: + m_menuRequested = false; + break; + case ui::SELECTION_HANDLE_DRAG_STARTED: + case ui::INSERTION_HANDLE_DRAG_STARTED: + m_handleDragInProgress = true; + break; + case ui::SELECTION_HANDLE_DRAG_STOPPED: + case ui::INSERTION_HANDLE_DRAG_STOPPED: + m_handleDragInProgress = false; + break; + case ui::SELECTION_HANDLES_MOVED: + case ui::INSERTION_HANDLE_MOVED: + break; + case ui::INSERTION_HANDLE_TAPPED: + m_menuRequested = !m_menuRequested; + break; + } + + updateMenu(); +} + +void TouchSelectionControllerClientQt::OnDragUpdate(const gfx::PointF& position) +{ + Q_UNUSED(position); +} + +std::unique_ptr<ui::TouchHandleDrawable> TouchSelectionControllerClientQt::CreateDrawable() +{ + return std::unique_ptr<ui::TouchHandleDrawable>(new TouchHandleDrawableQt(m_rwhv)); +} + +void TouchSelectionControllerClientQt::DidScroll() +{ +} + +void TouchSelectionControllerClientQt::showMenu() +{ + gfx::RectF rect = GetTouchSelectionController()->GetRectBetweenBounds(); + gfx::PointF origin = rect.origin(); + gfx::PointF bottom_right = rect.bottom_right(); + + gfx::Vector2dF diagonal = bottom_right - origin; + gfx::SizeF size(diagonal.x(), diagonal.y()); + gfx::RectF anchor_rect(origin, size); + + // Calculate maximum handle image size; + gfx::SizeF max_handle_size = GetTouchSelectionController()->GetStartHandleRect().size(); + max_handle_size.SetToMax(GetTouchSelectionController()->GetEndHandleRect().size()); + + WebContentsAdapterClient *adapterClient = m_rwhv->adapterClient(); + Q_ASSERT(adapterClient); + adapterClient->showTouchSelectionMenu(m_menuController.data(), + QRect(toQt(gfx::ToEnclosingRect(anchor_rect))), + QSize(toQt(gfx::ToRoundedSize(max_handle_size)))); + m_menuShowing = true; +} + +void TouchSelectionControllerClientQt::hideMenu() +{ + WebContentsAdapterClient *adapterClient = m_rwhv->adapterClient(); + Q_ASSERT(adapterClient); + adapterClient->hideTouchSelectionMenu(); + m_menuShowing = false; +} + +void TouchSelectionControllerClientQt::updateMenu() +{ + if (m_menuShowing) + hideMenu(); + + if (m_menuRequested && !m_touchDown && + !m_scrollInProgress && !m_handleDragInProgress) { + showMenu(); + } +} + +} // namespace QtWebEngineCore diff --git a/src/core/touch_selection_controller_client_qt.h b/src/core/touch_selection_controller_client_qt.h new file mode 100644 index 000000000..0d8dcf696 --- /dev/null +++ b/src/core/touch_selection_controller_client_qt.h @@ -0,0 +1,118 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TOUCH_SELECTION_CONTROLLER_CLIENT_QT_H +#define TOUCH_SELECTION_CONTROLLER_CLIENT_QT_H + +#include "content/public/browser/touch_selection_controller_client_manager.h" +#include "content/public/common/context_menu_params.h" +#include "ui/touch_selection/touch_selection_controller.h" +#include "ui/touch_selection/touch_selection_menu_runner.h" + +#include <QtCore/QScopedPointer> + +namespace QtWebEngineCore { + +class RenderWidgetHostViewQt; +class TouchSelectionMenuController; + +class TouchSelectionControllerClientQt + : public ui::TouchSelectionControllerClient + , public ui::TouchSelectionMenuClient + , public content::TouchSelectionControllerClientManager +{ +public: + explicit TouchSelectionControllerClientQt(RenderWidgetHostViewQt *rwhv); + ~TouchSelectionControllerClientQt() override; + + void UpdateClientSelectionBounds(const gfx::SelectionBound& start, + const gfx::SelectionBound& end); + bool handleContextMenu(const content::ContextMenuParams& params); + void onTouchDown(); + void onTouchUp(); + void onScrollBegin(); + void onScrollEnd(); + + // ui::TouchSelectionMenuClient overrides + bool IsCommandIdEnabled(int command_id) const override; + void ExecuteCommand(int command_id, int event_flags) override; + void RunContextMenu() override; + bool ShouldShowQuickMenu() override { return false; } + base::string16 GetSelectedText() override { return base::string16(); } + + // content::TouchSelectionControllerClientManager overrides + void DidStopFlinging() override; + void UpdateClientSelectionBounds(const gfx::SelectionBound& start, + const gfx::SelectionBound& end, + ui::TouchSelectionControllerClient* client, + ui::TouchSelectionMenuClient* menu_client) override; + void InvalidateClient(ui::TouchSelectionControllerClient* client) override; + ui::TouchSelectionController* GetTouchSelectionController() override; + void AddObserver(Observer* observer) override; + void RemoveObserver(Observer* observer) override; + + // ui::TouchSelectionControllerClient overrides + bool SupportsAnimation() const override; + void SetNeedsAnimate() override; + void MoveCaret(const gfx::PointF& position) override; + void MoveRangeSelectionExtent(const gfx::PointF& extent) override; + void SelectBetweenCoordinates(const gfx::PointF& base, const gfx::PointF& extent) override; + void OnSelectionEvent(ui::SelectionEventType event) override; + void OnDragUpdate(const gfx::PointF& position) override; + std::unique_ptr<ui::TouchHandleDrawable> CreateDrawable() override; + void DidScroll() override; + +private: + void showMenu(); + void hideMenu(); + void updateMenu(); + + RenderWidgetHostViewQt *m_rwhv; + QScopedPointer<TouchSelectionMenuController> m_menuController; + + bool m_menuShowing; + bool m_menuRequested; + bool m_touchDown; + bool m_scrollInProgress; + bool m_handleDragInProgress; +}; + +} // namespace QtWebEngineCore + +#endif // TOUCH_SELECTION_CONTROLLER_CLIENT_QT_H diff --git a/src/core/touch_selection_menu_controller.cpp b/src/core/touch_selection_menu_controller.cpp new file mode 100644 index 000000000..cdec9a064 --- /dev/null +++ b/src/core/touch_selection_menu_controller.cpp @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "touch_selection_controller_client_qt.h" +#include "touch_selection_menu_controller.h" + +namespace QtWebEngineCore { + +TouchSelectionMenuController::TouchSelectionMenuController(TouchSelectionControllerClientQt *touchSelectionControllerClient) + : m_touchSelectionControllerClient(touchSelectionControllerClient) +{ +} + +TouchSelectionMenuController::~TouchSelectionMenuController() +{ +} + +int TouchSelectionMenuController::buttonCount() +{ + int buttonCount = 1; + + for (int commandId = 0; commandId <= static_cast<int>(Paste); ++commandId) { + if (m_touchSelectionControllerClient->IsCommandIdEnabled(commandId)) + buttonCount++; + } + + return buttonCount; +} + +bool TouchSelectionMenuController::isCommandEnabled(TouchSelectionCommand command) +{ + return m_touchSelectionControllerClient->IsCommandIdEnabled(static_cast<int>(command)); +} + +void TouchSelectionMenuController::cut() +{ + m_touchSelectionControllerClient->ExecuteCommand(static_cast<int>(Cut), 0); +} + +void TouchSelectionMenuController::copy() +{ + m_touchSelectionControllerClient->ExecuteCommand(static_cast<int>(Copy), 0); +} + +void TouchSelectionMenuController::paste() +{ + m_touchSelectionControllerClient->ExecuteCommand(static_cast<int>(Paste), 0); +} + +void TouchSelectionMenuController::runContextMenu() +{ + return m_touchSelectionControllerClient->RunContextMenu(); +} + +} // namespace QtWebEngineCore diff --git a/src/core/touch_selection_menu_controller.h b/src/core/touch_selection_menu_controller.h new file mode 100644 index 000000000..34137b05b --- /dev/null +++ b/src/core/touch_selection_menu_controller.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TOUCH_SELECTION_MENU_CONTROLLER_H +#define TOUCH_SELECTION_MENU_CONTROLLER_H + +#include "qtwebenginecoreglobal_p.h" +#include <QtCore/QObject> + +namespace QtWebEngineCore { + +class TouchSelectionControllerClientQt; + +class Q_WEBENGINECORE_PRIVATE_EXPORT TouchSelectionMenuController : public QObject { + Q_OBJECT +public: + enum TouchSelectionCommand { + Cut, + Copy, + Paste + }; + + TouchSelectionMenuController(TouchSelectionControllerClientQt *touchSelectionControllerClient); + ~TouchSelectionMenuController(); + int buttonCount(); + bool isCommandEnabled(TouchSelectionCommand); + +public Q_SLOTS: + void cut(); + void copy(); + void paste(); + void runContextMenu(); + +private: + TouchSelectionControllerClientQt *m_touchSelectionControllerClient; +}; + +} // namespace QtWebEngineCore + +#endif // TOUCH_SELECTION_CONTROLLER_CLIENT_QT_H diff --git a/src/core/type_conversion.cpp b/src/core/type_conversion.cpp index f69b2a297..02d2db448 100644 --- a/src/core/type_conversion.cpp +++ b/src/core/type_conversion.cpp @@ -42,7 +42,9 @@ #include <content/public/common/favicon_url.h> #include <ui/events/event_constants.h> #include <ui/gfx/image/image_skia.h> + #include <QtCore/qcoreapplication.h> +#include <QtGui/qmatrix4x4.h> namespace QtWebEngineCore { @@ -131,7 +133,7 @@ QImage toQImage(const SkBitmap &bitmap) QImage toQImage(const gfx::ImageSkiaRep &imageSkiaRep) { - QImage image = toQImage(imageSkiaRep.sk_bitmap()); + QImage image = toQImage(imageSkiaRep.GetBitmap()); if (!image.isNull() && imageSkiaRep.scale() != 1.0f) image.setDevicePixelRatio(imageSkiaRep.scale()); return image; @@ -243,4 +245,15 @@ FaviconInfo toFaviconInfo(const content::FaviconURL &favicon_url) return info; } +void convertToQt(const SkMatrix44 &m, QMatrix4x4 &c) +{ + QMatrix4x4 qtMatrix( + m.get(0, 0), m.get(0, 1), m.get(0, 2), m.get(0, 3), + m.get(1, 0), m.get(1, 1), m.get(1, 2), m.get(1, 3), + m.get(2, 0), m.get(2, 1), m.get(2, 2), m.get(2, 3), + m.get(3, 0), m.get(3, 1), m.get(3, 2), m.get(3, 3)); + qtMatrix.optimize(); + c = qtMatrix; +} + } // namespace QtWebEngineCore diff --git a/src/core/type_conversion.h b/src/core/type_conversion.h index afc3c3336..7b1f1b4d6 100644 --- a/src/core/type_conversion.h +++ b/src/core/type_conversion.h @@ -45,7 +45,6 @@ #include <QDir> #include <QIcon> #include <QImage> -#include <QMatrix4x4> #include <QNetworkCookie> #include <QRect> #include <QString> @@ -64,6 +63,8 @@ #include "ui/gfx/geometry/rect_f.h" #include "url/gurl.h" +QT_FORWARD_DECLARE_CLASS(QMatrix4x4) + namespace content { struct FaviconURL; } @@ -171,6 +172,11 @@ inline gfx::SizeF toGfx(const QSizeF& size) return gfx::SizeF(size.width(), size.height()); } +inline gfx::Rect toGfx(const QRect &rect) +{ + return gfx::Rect(rect.x(), rect.y(), rect.width(), rect.height()); +} + inline QSizeF toQt(const gfx::SizeF &size) { return QSizeF(size.width(), size.height()); @@ -198,16 +204,7 @@ SkBitmap toSkBitmap(const QImage &image); QIcon toQIcon(const std::vector<SkBitmap> &bitmaps); -inline QMatrix4x4 toQt(const SkMatrix44 &m) -{ - QMatrix4x4 qtMatrix( - m.get(0, 0), m.get(0, 1), m.get(0, 2), m.get(0, 3), - m.get(1, 0), m.get(1, 1), m.get(1, 2), m.get(1, 3), - m.get(2, 0), m.get(2, 1), m.get(2, 2), m.get(2, 3), - m.get(3, 0), m.get(3, 1), m.get(3, 2), m.get(3, 3)); - qtMatrix.optimize(); - return qtMatrix; -} +void convertToQt(const SkMatrix44 &m, QMatrix4x4 &c); inline QDateTime toQt(base::Time time) { diff --git a/src/core/user_notification_controller.cpp b/src/core/user_notification_controller.cpp new file mode 100644 index 000000000..d169bf854 --- /dev/null +++ b/src/core/user_notification_controller.cpp @@ -0,0 +1,216 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "user_notification_controller.h" + +#include "type_conversion.h" + +#include "base/callback.h" +#include "content/public/browser/notification_event_dispatcher.h" +#include "third_party/blink/public/common/notifications/notification_resources.h" +#include "third_party/blink/public/common/notifications/platform_notification_data.h" +#include "ui/message_center/public/cpp/notification_delegate.h" + +#include <memory> + +namespace QtWebEngineCore { + +static Qt::LayoutDirection toDirection(blink::PlatformNotificationData::Direction direction) +{ + switch (direction) { + case blink::PlatformNotificationData::DIRECTION_LEFT_TO_RIGHT: + return Qt::LeftToRight; + case blink::PlatformNotificationData::DIRECTION_RIGHT_TO_LEFT: + return Qt::RightToLeft; + case blink::PlatformNotificationData::DIRECTION_AUTO: + default: + break; + } + return Qt::LayoutDirectionAuto; +} + +class UserNotificationControllerPrivate { +public: + UserNotificationControllerPrivate(const blink::PlatformNotificationData ¶ms, + const blink::NotificationResources &resources, + const GURL &origin) + : m_params(params) + , m_origin(origin) + , m_delegate(nullptr) + , m_resources(resources) + , m_client(nullptr) + , m_iconGenerated(false) + , m_imageGenerated(false) + , m_badgeGenerated(false) + , m_shown(false) + { } + + blink::PlatformNotificationData m_params; + GURL m_origin; + std::unique_ptr<UserNotificationController::Delegate> m_delegate; + blink::NotificationResources m_resources; + UserNotificationController::Client *m_client; + QImage m_icon; + QImage m_image; + QImage m_badge; + bool m_iconGenerated; + bool m_imageGenerated; + bool m_badgeGenerated; + bool m_shown; +}; + + +UserNotificationController::UserNotificationController(const blink::PlatformNotificationData ¶ms, + const blink::NotificationResources &resources, + const GURL &origin, + Delegate *delegate) + : d(new UserNotificationControllerPrivate(params, resources, origin)) +{ + d->m_delegate.reset(delegate); +} + +UserNotificationController::~UserNotificationController() +{ + delete d; + d = nullptr; +} + +void UserNotificationController::notificationDisplayed() +{ + if (!d->m_shown) { + d->m_shown = true; + if (d->m_delegate) + d->m_delegate->shown(); + } +} + +void UserNotificationController::notificationClosed() +{ + d->m_shown = false; + if (d->m_delegate) + d->m_delegate->closed(true); +} + +void UserNotificationController::notificationClicked() +{ + if (d->m_delegate) + d->m_delegate->clicked(); +} + +void UserNotificationController::closeNotification() +{ + d->m_shown = false; + if (d->m_client) + d->m_client->notificationClosed(this); +} + +void UserNotificationController::setClient(UserNotificationController::Client* client) +{ + d->m_client = client; +} + +UserNotificationController::Client* UserNotificationController::client() +{ + return d->m_client; +} + +QUrl UserNotificationController::origin() const +{ + return toQt(d->m_origin); +} + +QImage UserNotificationController::icon() const +{ + if (!d->m_iconGenerated) { + d->m_iconGenerated = true; + if (!d->m_resources.notification_icon.isNull()) + d->m_icon = toQImage(d->m_resources.notification_icon); + } + return d->m_icon; +} + +QImage UserNotificationController::image() const +{ + if (d->m_imageGenerated) + return d->m_image; + d->m_image = toQImage(d->m_resources.image); + d->m_imageGenerated = true; + return d->m_image; +} + +QImage UserNotificationController::badge() const +{ + if (d->m_badgeGenerated) + return d->m_badge; + d->m_badge = toQImage(d->m_resources.badge); + d->m_badgeGenerated = true; + return d->m_badge; +} + +QString UserNotificationController::title() const +{ + return toQt(d->m_params.title); +} + +QString UserNotificationController::body() const +{ + return toQt(d->m_params.body); +} + +QString UserNotificationController::tag() const +{ + return toQt(d->m_params.tag); +} + +QString UserNotificationController::language() const +{ + return toQt(d->m_params.lang); +} + +Qt::LayoutDirection UserNotificationController::direction() const +{ + return toDirection(d->m_params.direction); +} + +bool UserNotificationController::isShown() const +{ + return d->m_shown; +} + +} // namespace QtWebEngineCore diff --git a/src/core/user_notification_controller.h b/src/core/user_notification_controller.h new file mode 100644 index 000000000..bab85c7ec --- /dev/null +++ b/src/core/user_notification_controller.h @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DESKTOP_NOTIFICATION_CONTROLLER_H +#define DESKTOP_NOTIFICATION_CONTROLLER_H + +#include "qtwebenginecoreglobal.h" + +#include <QtCore/QSharedPointer> +#include <QtCore/QUrl> +#include <QtGui/QIcon> + +class GURL; + +namespace blink { + struct NotificationResources; + struct PlatformNotificationData; +} + +namespace QtWebEngineCore { + +class UserNotificationControllerPrivate; + +// Works as an accessor and owner of chromium objects related to showing desktop notifications. +class Q_WEBENGINECORE_EXPORT UserNotificationController : public QEnableSharedFromThis<UserNotificationController> { +public: + struct Delegate { + virtual ~Delegate() { } + virtual void shown() = 0; + virtual void clicked() = 0; + virtual void closed(bool byUser) = 0; + }; + + UserNotificationController(const blink::PlatformNotificationData ¶ms, + const blink::NotificationResources &resources, + const GURL &origin, + Delegate *delegate); + ~UserNotificationController(); + + // The notification was shown. + void notificationDisplayed(); + + // The notification was closed. + void notificationClosed(); + + // The user clicked on the notification. + void notificationClicked(); + + // Chromium requests to close the notification. + void closeNotification(); + + QUrl origin() const; + QImage icon() const; + QImage image() const; + QImage badge() const; + QString title() const; + QString body() const; + QString tag() const; + QString language() const; + Qt::LayoutDirection direction() const; + + bool isShown() const; + + class Client { + public: + virtual ~Client() { } + virtual void notificationClosed(const UserNotificationController *) = 0; + }; + void setClient(Client *client); + Client* client(); + +private: + UserNotificationControllerPrivate *d; +}; + +} // namespace QtWebEngineCore + +#endif // DESKTOP_NOTIFICATION_CONTROLLER_H diff --git a/src/core/user_script.h b/src/core/user_script.h index 5ad53fdc1..8f65f4b74 100644 --- a/src/core/user_script.h +++ b/src/core/user_script.h @@ -63,7 +63,7 @@ namespace QtWebEngineCore { class UserResourceControllerHost; -class QWEBENGINECORE_PRIVATE_EXPORT UserScript : public QSharedData { +class Q_WEBENGINECORE_PRIVATE_EXPORT UserScript : public QSharedData { public: enum InjectionPoint { AfterLoad, diff --git a/src/core/visited_links_manager_qt.cpp b/src/core/visited_links_manager_qt.cpp index ac27446b8..d4885e8e8 100644 --- a/src/core/visited_links_manager_qt.cpp +++ b/src/core/visited_links_manager_qt.cpp @@ -39,7 +39,6 @@ #include "visited_links_manager_qt.h" -#include "profile_adapter.h" #include "content_browser_client_qt.h" #include "profile_qt.h" #include "type_conversion.h" @@ -106,14 +105,13 @@ static void ensureDirectoryExists(const base::FilePath &path) errorstr.c_str()); } -VisitedLinksManagerQt::VisitedLinksManagerQt(ProfileAdapter *adapter) +VisitedLinksManagerQt::VisitedLinksManagerQt(ProfileQt *profile, bool persistVisitedLinks) : m_delegate(new VisitedLinkDelegateQt) { - Q_ASSERT(adapter && adapter->profile()); - ProfileQt *profile = adapter->profile(); - if (adapter->persistVisitedLinks()) + Q_ASSERT(profile); + if (persistVisitedLinks) ensureDirectoryExists(profile->GetPath()); - m_visitedLinkMaster.reset(new visitedlink::VisitedLinkMaster(profile, m_delegate.data(), adapter->persistVisitedLinks())); + m_visitedLinkMaster.reset(new visitedlink::VisitedLinkMaster(profile, m_delegate.data(), persistVisitedLinks)); m_visitedLinkMaster->Init(); } diff --git a/src/core/visited_links_manager_qt.h b/src/core/visited_links_manager_qt.h index 8d9a7495b..ecac8f30f 100644 --- a/src/core/visited_links_manager_qt.h +++ b/src/core/visited_links_manager_qt.h @@ -67,14 +67,14 @@ class GURL; namespace QtWebEngineCore { -class ProfileAdapter; +class ProfileQt; class VisitedLinkDelegateQt; -class QWEBENGINECORE_PRIVATE_EXPORT VisitedLinksManagerQt { +class Q_WEBENGINECORE_PRIVATE_EXPORT VisitedLinksManagerQt { public: virtual~VisitedLinksManagerQt(); - VisitedLinksManagerQt(ProfileAdapter *profileAdapter); + VisitedLinksManagerQt(ProfileQt *profile, bool persistVisitedLinks); void deleteAllVisitedLinkData(); void deleteVisitedLinkDataForUrls(const QList<QUrl> &); diff --git a/src/core/web_contents_adapter.cpp b/src/core/web_contents_adapter.cpp index f74f16bc3..ca2479965 100644 --- a/src/core/web_contents_adapter.cpp +++ b/src/core/web_contents_adapter.cpp @@ -43,18 +43,17 @@ #include "web_contents_adapter.h" -#include "browser_accessibility_qt.h" -#include "profile_adapter_client.h" -#include "profile_adapter.h" #include "devtools_frontend_qt.h" #include "download_manager_delegate_qt.h" #include "media_capture_devices_dispatcher.h" #if QT_CONFIG(webengine_printing_and_pdf) #include "printing/print_view_manager_qt.h" #endif +#include "profile_adapter_client.h" +#include "profile_adapter.h" #include "profile_qt.h" #include "qwebenginecallback_p.h" -#include "render_view_observer_host_qt.h" +#include "renderer_host/render_view_observer_host_qt.h" #include "render_widget_host_view_qt.h" #include "type_conversion.h" #include "web_contents_view_qt.h" @@ -62,10 +61,13 @@ #include "web_engine_settings.h" #include "base/command_line.h" +#include "base/message_loop/message_loop_impl.h" #include "base/run_loop.h" +#include "base/task/post_task.h" #include "base/values.h" #include "content/browser/renderer_host/render_view_host_impl.h" #include "content/browser/web_contents/web_contents_impl.h" +#include "content/public/browser/browser_task_traits.h" #include "content/public/browser/child_process_security_policy.h" #include "content/public/browser/devtools_agent_host.h" #include "content/public/browser/download_manager.h" @@ -83,10 +85,13 @@ #include "content/public/common/url_constants.h" #include "content/public/common/web_preferences.h" #include "content/public/common/webrtc_ip_handling_policy.h" -#include "third_party/blink/public/web/web_find_options.h" +#include "extensions/buildflags/buildflags.h" +#include "third_party/blink/public/mojom/frame/find_in_page.mojom.h" +//#include "third_party/blink/public/web/web_find_options.h" #include "third_party/blink/public/web/web_media_player_action.h" #include "printing/buildflags/buildflags.h" #include "ui/base/clipboard/clipboard.h" +#include "ui/base/clipboard/clipboard_constants.h" #include "ui/base/clipboard/custom_data_helper.h" #include "ui/gfx/font_render_params.h" @@ -95,6 +100,10 @@ #include <QtWebChannel/QWebChannel> #endif +#if BUILDFLAG(ENABLE_EXTENSIONS) +#include "extensions/extension_web_contents_observer_qt.h" +#endif + #include <QDir> #include <QGuiApplication> #include <QPageLayout> @@ -105,10 +114,14 @@ #include <QtCore/qelapsedtimer.h> #include <QtCore/qmimedata.h> #include <QtCore/qtemporarydir.h> -#include <QtGui/qaccessible.h> #include <QtGui/qdrag.h> #include <QtGui/qpixmap.h> +// Can't include headers as qaccessible.h conflicts with Chromium headers. +namespace content { +extern QAccessibleInterface *toQAccessibleInterface(BrowserAccessibility *acc); +} + namespace QtWebEngineCore { #define CHECK_INITIALIZED(return_value) \ @@ -117,7 +130,7 @@ namespace QtWebEngineCore { #define CHECK_VALID_RENDER_WIDGET_HOST_VIEW(render_view_host) \ if (!render_view_host->IsRenderViewLive() && render_view_host->GetWidget()->GetView()) { \ - qWarning("Ignore navigation due to terminated render process with invalid RenderWidgetHostView."); \ + LOG(WARNING) << "Ignore navigation due to terminated render process with invalid RenderWidgetHostView."; \ return; \ } @@ -190,7 +203,7 @@ static QVariant fromJSValue(const base::Value *result) } case base::Value::Type::BINARY: { - QByteArray data(result->GetBlob().data(), result->GetBlob().size()); + QByteArray data(reinterpret_cast<const char *>(result->GetBlob().data()), result->GetBlob().size()); ret.setValue(data); break; } @@ -210,10 +223,10 @@ static void callbackOnEvaluateJS(WebContentsAdapterClient *adapterClient, quint6 #if QT_CONFIG(webengine_printing_and_pdf) static void callbackOnPrintingFinished(WebContentsAdapterClient *adapterClient, int requestId, - const std::vector<char>& result) + QSharedPointer<QByteArray> result) { if (requestId) - adapterClient->didPrintPage(requestId, QByteArray(result.data(), result.size())); + adapterClient->didPrintPage(requestId, result); } static void callbackOnPdfSavingFinished(WebContentsAdapterClient *adapterClient, @@ -229,12 +242,16 @@ static std::unique_ptr<content::WebContents> createBlankWebContents(WebContentsA content::WebContents::CreateParams create_params(browserContext, NULL); create_params.routing_id = MSG_ROUTING_NONE; create_params.initial_size = gfx::Size(kTestWindowWidth, kTestWindowHeight); - create_params.context = reinterpret_cast<gfx::NativeView>(adapterClient); create_params.initially_hidden = true; - return content::WebContents::Create(create_params); + + std::unique_ptr<content::WebContents> webContents = content::WebContents::Create(create_params); + WebContentsViewQt* contentsView = static_cast<WebContentsViewQt*>(static_cast<content::WebContentsImpl*>(webContents.get())->GetView()); + contentsView->setClient(adapterClient); + + return webContents; } -static void serializeNavigationHistory(const content::NavigationController &controller, QDataStream &output) +static void serializeNavigationHistory(content::NavigationController &controller, QDataStream &output) { const int currentIndex = controller.GetCurrentEntryIndex(); const int count = controller.GetEntryCount(); @@ -246,7 +263,7 @@ static void serializeNavigationHistory(const content::NavigationController &cont // Logic taken from SerializedNavigationEntry::WriteToPickle. for (int i = 0; i < count; ++i) { - const content::NavigationEntry* entry = (i == pendingIndex) + content::NavigationEntry* entry = (i == pendingIndex) ? controller.GetPendingEntry() : controller.GetEntryAtIndex(i); if (entry->GetVirtualURL().is_valid()) { @@ -318,7 +335,7 @@ static void deserializeNavigationHistory(QDataStream &input, int *currentIndex, std::unique_ptr<content::NavigationEntry> entry = content::NavigationController::CreateNavigationEntry( toGurl(virtualUrl), - content::Referrer(toGurl(referrerUrl), static_cast<blink::WebReferrerPolicy>(referrerPolicy)), + content::Referrer(toGurl(referrerUrl), static_cast<network::mojom::ReferrerPolicy>(referrerPolicy)), // Use a transition type of reload so that we don't incorrectly // increase the typed count. ui::PAGE_TRANSITION_RELOAD, @@ -457,7 +474,6 @@ void WebContentsAdapter::initialize(content::SiteInstance *site) if (!m_webContents) { content::WebContents::CreateParams create_params(m_profileAdapter->profile(), site); create_params.initial_size = gfx::Size(kTestWindowWidth, kTestWindowHeight); - create_params.context = reinterpret_cast<gfx::NativeView>(m_adapterClient); create_params.initially_hidden = true; m_webContents = content::WebContents::Create(create_params); } @@ -480,7 +496,7 @@ void WebContentsAdapter::initialize(content::SiteInstance *site) #endif // Set web-contents font settings to the default font settings as Chromium constantly overrides // the global font defaults with the font settings of the latest web-contents created. - CR_DEFINE_STATIC_LOCAL(const gfx::FontRenderParams, params, (gfx::GetFontRenderParams(gfx::FontRenderParamsQuery(), NULL))); + static const gfx::FontRenderParams params = gfx::GetFontRenderParams(gfx::FontRenderParamsQuery(), nullptr); rendererPrefs->should_antialias_text = params.antialiasing; rendererPrefs->use_subpixel_positioning = params.subpixel_positioning; rendererPrefs->hinting = params.hinting; @@ -495,7 +511,7 @@ void WebContentsAdapter::initialize(content::SiteInstance *site) // Let the WebContent's view know about the WebContentsAdapterClient. WebContentsViewQt* contentsView = static_cast<WebContentsViewQt*>(static_cast<content::WebContentsImpl*>(m_webContents.get())->GetView()); - contentsView->initialize(m_adapterClient); + contentsView->setClient(m_adapterClient); // This should only be necessary after having restored the history to a new WebContentsAdapter. m_webContents->GetController().LoadIfNecessary(); @@ -503,6 +519,9 @@ void WebContentsAdapter::initialize(content::SiteInstance *site) #if QT_CONFIG(webengine_printing_and_pdf) PrintViewManagerQt::CreateForWebContents(webContents()); #endif +#if BUILDFLAG(ENABLE_EXTENSIONS) + extensions::ExtensionWebContentsObserverQt::CreateForWebContents(webContents()); +#endif // Create an instance of WebEngineVisitedLinksManager to catch the first // content::NOTIFICATION_RENDERER_PROCESS_CREATED event. This event will @@ -630,7 +649,6 @@ void WebContentsAdapter::load(const QWebEngineHttpRequest &request) "HTTP-POST data can only be sent over HTTP(S) protocol")); return; } - params.post_data = network::ResourceRequestBody::CreateFromBytes( (const char*)request.postData().constData(), request.postData().length()); @@ -666,8 +684,8 @@ void WebContentsAdapter::load(const QWebEngineHttpRequest &request) QWeakPointer<WebContentsAdapter> weakThis(sharedFromThis()); if (resizeNeeded) { // Schedule navigation on the event loop. - content::BrowserThread::PostTask( - content::BrowserThread::UI, FROM_HERE, base::BindOnce(navigate, std::move(weakThis), std::move(params))); + base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(navigate, std::move(weakThis), std::move(params))); } else { navigate(std::move(weakThis), params); } @@ -804,7 +822,7 @@ void WebContentsAdapter::selectAll() void WebContentsAdapter::requestClose() { CHECK_INITIALIZED(); - m_webContents->DispatchBeforeUnload(); + m_webContents->DispatchBeforeUnload(false /* auto_cancel */); } void WebContentsAdapter::unselect() @@ -936,8 +954,8 @@ QAccessibleInterface *WebContentsAdapter::browserAccessible() if (!manager) // FIXME! return nullptr; content::BrowserAccessibility *acc = manager->GetRoot(); - content::BrowserAccessibilityQt *accQt = static_cast<content::BrowserAccessibilityQt*>(acc); - return accQt; + + return content::toQAccessibleInterface(acc); } #endif // QT_NO_ACCESSIBILITY @@ -995,16 +1013,16 @@ quint64 WebContentsAdapter::findText(const QString &subString, bool caseSensitiv m_adapterClient->didFindText(m_lastFindRequestId, 0); } - blink::WebFindOptions options; - options.forward = !findBackward; - options.match_case = caseSensitively; - options.find_next = subString == m_webContentsDelegate->lastSearchedString(); + blink::mojom::FindOptionsPtr options = blink::mojom::FindOptions::New(); + options->forward = !findBackward; + options->match_case = caseSensitively; + options->find_next = subString == m_webContentsDelegate->lastSearchedString(); m_webContentsDelegate->setLastSearchedString(subString); // Find already allows a request ID as input, but only as an int. // Use the same counter but mod it to MAX_INT, this keeps the same likeliness of request ID clashing. int shrunkRequestId = m_nextRequestId++ & 0x7fffffff; - m_webContents->Find(shrunkRequestId, toString16(subString), options); + m_webContents->Find(shrunkRequestId, toString16(subString), std::move(options)); m_lastFindRequestId = shrunkRequestId; return shrunkRequestId; } @@ -1074,7 +1092,7 @@ void WebContentsAdapter::download(const QUrl &url, const QString &suggestedFileN content::Referrer referrer = content::Referrer::SanitizeForRequest( gurl, content::Referrer(toGurl(referrerUrl).GetAsReferrer(), - static_cast<blink::WebReferrerPolicy>(referrerPolicy))); + static_cast<network::mojom::ReferrerPolicy>(referrerPolicy))); params->set_referrer(referrer.url); params->set_referrer_policy(content::Referrer::ReferrerPolicyForUrlRequest(referrer.policy)); @@ -1106,16 +1124,30 @@ void WebContentsAdapter::copyImageAt(const QPoint &location) m_webContents->GetRenderViewHost()->GetMainFrame()->CopyImageAt(location.x(), location.y()); } -ASSERT_ENUMS_MATCH(WebContentsAdapter::MediaPlayerNoAction, blink::WebMediaPlayerAction::kUnknown) -ASSERT_ENUMS_MATCH(WebContentsAdapter::MediaPlayerPlay, blink::WebMediaPlayerAction::kPlay) -ASSERT_ENUMS_MATCH(WebContentsAdapter::MediaPlayerMute, blink::WebMediaPlayerAction::kMute) -ASSERT_ENUMS_MATCH(WebContentsAdapter::MediaPlayerLoop, blink::WebMediaPlayerAction::kLoop) -ASSERT_ENUMS_MATCH(WebContentsAdapter::MediaPlayerControls, blink::WebMediaPlayerAction::kControls) +static blink::WebMediaPlayerAction::Type toBlinkMediaPlayerActionType(WebContentsAdapter::MediaPlayerAction action) +{ + switch (action) { + case WebContentsAdapter::MediaPlayerPlay: + return blink::WebMediaPlayerAction::Type::kPlay; + case WebContentsAdapter::MediaPlayerMute: + return blink::WebMediaPlayerAction::Type::kMute; + case WebContentsAdapter::MediaPlayerLoop: + return blink::WebMediaPlayerAction::Type::kLoop; + case WebContentsAdapter::MediaPlayerControls: + return blink::WebMediaPlayerAction::Type::kControls; + case WebContentsAdapter::MediaPlayerNoAction: + break; + } + NOTREACHED(); + return (blink::WebMediaPlayerAction::Type)-1; +} void WebContentsAdapter::executeMediaPlayerActionAt(const QPoint &location, MediaPlayerAction action, bool enable) { CHECK_INITIALIZED(); - blink::WebMediaPlayerAction blinkAction((blink::WebMediaPlayerAction::Type)action, enable); + if (action == MediaPlayerNoAction) + return; + blink::WebMediaPlayerAction blinkAction(toBlinkMediaPlayerActionType(action), enable); m_webContents->GetRenderViewHost()->GetMainFrame()->ExecuteMediaPlayerActionAtLocation(toGfx(location), blinkAction); } @@ -1263,6 +1295,12 @@ void WebContentsAdapter::runGeolocationRequestCallback(const QUrl &securityOrigi m_profileAdapter->permissionRequestReply(securityOrigin, ProfileAdapter::GeolocationPermission, allowed); } +void WebContentsAdapter::runUserNotificationRequestCallback(const QUrl &securityOrigin, bool allowed) +{ + CHECK_INITIALIZED(); + m_profileAdapter->permissionRequestReply(securityOrigin, ProfileAdapter::NotificationPermission, allowed); +} + void WebContentsAdapter::grantMouseLockPermission(bool granted) { CHECK_INITIALIZED(); @@ -1277,16 +1315,6 @@ void WebContentsAdapter::grantMouseLockPermission(bool granted) m_webContents->GotResponseToLockMouseRequest(granted); } -void WebContentsAdapter::dpiScaleChanged() -{ - CHECK_INITIALIZED(); - content::RenderWidgetHostImpl* impl = NULL; - if (m_webContents->GetRenderViewHost()) - impl = content::RenderWidgetHostImpl::From(m_webContents->GetRenderViewHost()->GetWidget()); - if (impl) - impl->NotifyScreenInfoChanged(); -} - void WebContentsAdapter::setBackgroundColor(const QColor &color) { CHECK_INITIALIZED(); @@ -1344,7 +1372,7 @@ static QMimeData *mimeDataFromDropData(const content::DropData &dropData) if (!dropData.custom_data.empty()) { base::Pickle pickle; ui::WriteCustomDataToPickle(dropData.custom_data, &pickle); - mimeData->setData(toQt(ui::Clipboard::GetWebCustomDataFormatType().ToString()), QByteArray((const char*)pickle.data(), pickle.size())); + mimeData->setData(QLatin1String(ui::kMimeTypeWebCustomData), QByteArray((const char*)pickle.data(), pickle.size())); } return mimeData; } @@ -1396,7 +1424,7 @@ void WebContentsAdapter::startDragging(QObject *dragSource, const content::DropD } { - base::MessageLoop::ScopedNestableTaskAllower allow; + base::MessageLoopCurrent::ScopedNestableTaskAllower allow; drag->exec(allowedActions); } @@ -1462,8 +1490,8 @@ static void fillDropDataFromMimeData(content::DropData *dropData, const QMimeDat dropData->html = toNullableString16(mimeData->html()); if (mimeData->hasText()) dropData->text = toNullableString16(mimeData->text()); - if (mimeData->hasFormat(toQt(ui::Clipboard::GetWebCustomDataFormatType().ToString()))) { - QByteArray customData = mimeData->data(toQt(ui::Clipboard::GetWebCustomDataFormatType().ToString())); + if (mimeData->hasFormat(QLatin1String(ui::kMimeTypeWebCustomData))) { + QByteArray customData = mimeData->data(QLatin1String(ui::kMimeTypeWebCustomData)); ui::ReadCustomDataIntoMap(customData.constData(), customData.length(), &dropData->custom_data); } } @@ -1540,7 +1568,7 @@ void WebContentsAdapter::waitForUpdateDragActionCalled() const qint64 timeout = 3000; QElapsedTimer t; t.start(); - base::MessagePump::Delegate *delegate = base::MessageLoop::current(); + base::MessagePump::Delegate *delegate = static_cast<base::MessageLoopImpl *>(base::MessageLoopCurrent::Get().ToMessageLoopBaseDeprecated()); DCHECK(delegate); m_updateDragActionCalled = false; for (;;) { @@ -1675,15 +1703,15 @@ ASSERT_ENUMS_MATCH(WebContentsAdapterClient::SaveToDiskDisposition, WindowOpenDi ASSERT_ENUMS_MATCH(WebContentsAdapterClient::OffTheRecordDisposition, WindowOpenDisposition::OFF_THE_RECORD) ASSERT_ENUMS_MATCH(WebContentsAdapterClient::IgnoreActionDisposition, WindowOpenDisposition::IGNORE_ACTION) -ASSERT_ENUMS_MATCH(ReferrerPolicy::Always, blink::kWebReferrerPolicyAlways) -ASSERT_ENUMS_MATCH(ReferrerPolicy::Default, blink::kWebReferrerPolicyDefault) -ASSERT_ENUMS_MATCH(ReferrerPolicy::NoReferrerWhenDowngrade, blink::kWebReferrerPolicyNoReferrerWhenDowngrade) -ASSERT_ENUMS_MATCH(ReferrerPolicy::Never, blink::kWebReferrerPolicyNever) -ASSERT_ENUMS_MATCH(ReferrerPolicy::Origin, blink::kWebReferrerPolicyOrigin) -ASSERT_ENUMS_MATCH(ReferrerPolicy::OriginWhenCrossOrigin, blink::kWebReferrerPolicyOriginWhenCrossOrigin) -ASSERT_ENUMS_MATCH(ReferrerPolicy::NoReferrerWhenDowngradeOriginWhenCrossOrigin, blink::kWebReferrerPolicyNoReferrerWhenDowngradeOriginWhenCrossOrigin) -ASSERT_ENUMS_MATCH(ReferrerPolicy::SameOrigin, blink::kWebReferrerPolicySameOrigin) -ASSERT_ENUMS_MATCH(ReferrerPolicy::StrictOrigin, blink::kWebReferrerPolicyStrictOrigin) -ASSERT_ENUMS_MATCH(ReferrerPolicy::Last, blink::kWebReferrerPolicyLast) +ASSERT_ENUMS_MATCH(ReferrerPolicy::Always, network::mojom::ReferrerPolicy::kAlways) +ASSERT_ENUMS_MATCH(ReferrerPolicy::Default, network::mojom::ReferrerPolicy::kDefault) +ASSERT_ENUMS_MATCH(ReferrerPolicy::NoReferrerWhenDowngrade, network::mojom::ReferrerPolicy::kNoReferrerWhenDowngrade) +ASSERT_ENUMS_MATCH(ReferrerPolicy::Never, network::mojom::ReferrerPolicy::kNever) +ASSERT_ENUMS_MATCH(ReferrerPolicy::Origin, network::mojom::ReferrerPolicy::kOrigin) +ASSERT_ENUMS_MATCH(ReferrerPolicy::OriginWhenCrossOrigin, network::mojom::ReferrerPolicy::kOriginWhenCrossOrigin) +ASSERT_ENUMS_MATCH(ReferrerPolicy::NoReferrerWhenDowngradeOriginWhenCrossOrigin, network::mojom::ReferrerPolicy::kNoReferrerWhenDowngradeOriginWhenCrossOrigin) +ASSERT_ENUMS_MATCH(ReferrerPolicy::SameOrigin, network::mojom::ReferrerPolicy::kSameOrigin) +ASSERT_ENUMS_MATCH(ReferrerPolicy::StrictOrigin, network::mojom::ReferrerPolicy::kStrictOrigin) +ASSERT_ENUMS_MATCH(ReferrerPolicy::Last, network::mojom::ReferrerPolicy::kLast) } // namespace QtWebEngineCore diff --git a/src/core/web_contents_adapter.h b/src/core/web_contents_adapter.h index 9f9d0ed03..da4bc9190 100644 --- a/src/core/web_contents_adapter.h +++ b/src/core/web_contents_adapter.h @@ -91,7 +91,7 @@ class RenderViewObserverHostQt; class WebChannelIPCTransportHost; class WebEngineContext; -class QWEBENGINECORE_PRIVATE_EXPORT WebContentsAdapter : public QEnableSharedFromThis<WebContentsAdapter> { +class Q_WEBENGINECORE_PRIVATE_EXPORT WebContentsAdapter : public QEnableSharedFromThis<WebContentsAdapter> { public: static QSharedPointer<WebContentsAdapter> createFromSerializedNavigationHistory(QDataStream &input, WebContentsAdapterClient *adapterClient); WebContentsAdapter(); @@ -183,8 +183,8 @@ public: void grantMediaAccessPermission(const QUrl &securityOrigin, WebContentsAdapterClient::MediaRequestFlags flags); void runGeolocationRequestCallback(const QUrl &securityOrigin, bool allowed); void grantMouseLockPermission(bool granted); + void runUserNotificationRequestCallback(const QUrl &securityOrigin, bool allowed); - void dpiScaleChanged(); void setBackgroundColor(const QColor &color); QAccessibleInterface *browserAccessible(); ProfileQt* profile(); diff --git a/src/core/web_contents_adapter_client.h b/src/core/web_contents_adapter_client.h index 129e97c5b..540dd5f1f 100644 --- a/src/core/web_contents_adapter_client.h +++ b/src/core/web_contents_adapter_client.h @@ -66,6 +66,7 @@ QT_FORWARD_DECLARE_CLASS(QKeyEvent) QT_FORWARD_DECLARE_CLASS(QVariant) QT_FORWARD_DECLARE_CLASS(QWebEngineQuotaRequest) QT_FORWARD_DECLARE_CLASS(QWebEngineRegisterProtocolHandlerRequest) +QT_FORWARD_DECLARE_CLASS(QWebEngineUrlRequestInfo) namespace content { struct DropData; @@ -81,6 +82,8 @@ class JavaScriptDialogController; class RenderWidgetHostViewQt; class RenderWidgetHostViewQtDelegate; class RenderWidgetHostViewQtDelegateClient; +class TouchHandleDrawableClient; +class TouchSelectionMenuController; class WebContentsAdapter; class WebContentsDelegateQt; class WebEngineSettings; @@ -340,7 +343,7 @@ private: }; -class QWEBENGINECORE_PRIVATE_EXPORT WebContentsAdapterClient { +class Q_WEBENGINECORE_PRIVATE_EXPORT WebContentsAdapterClient { public: // This must match window_open_disposition_list.h. enum WindowOpenDisposition { @@ -421,7 +424,6 @@ public: virtual void selectionChanged() = 0; virtual void recentlyAudibleChanged(bool recentlyAudible) = 0; virtual QRectF viewportRect() const = 0; - virtual qreal dpiScale() const = 0; virtual QColor backgroundColor() const = 0; virtual void loadStarted(const QUrl &provisionalUrl, bool isErrorPage = false) = 0; virtual void loadCommitted() = 0; @@ -444,7 +446,7 @@ public: virtual void didFetchDocumentMarkup(quint64 requestId, const QString& result) = 0; virtual void didFetchDocumentInnerText(quint64 requestId, const QString& result) = 0; virtual void didFindText(quint64 requestId, int matchCount) = 0; - virtual void didPrintPage(quint64 requestId, const QByteArray &result) = 0; + virtual void didPrintPage(quint64 requestId, QSharedPointer<QByteArray>) = 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 @@ -457,6 +459,7 @@ public: virtual void runMouseLockPermissionRequest(const QUrl &securityOrigin) = 0; virtual void runQuotaRequest(QWebEngineQuotaRequest) = 0; virtual void runRegisterProtocolHandlerRequest(QWebEngineRegisterProtocolHandlerRequest) = 0; + virtual void runUserNotificationPermissionRequest(const QUrl &securityOrigin) = 0; virtual WebEngineSettings *webEngineSettings() const = 0; RenderProcessTerminationStatus renderProcessExitStatus(int); virtual void renderProcessTerminated(RenderProcessTerminationStatus terminationStatus, int exitCode) = 0; @@ -476,6 +479,10 @@ public: virtual ClientType clientType() = 0; virtual void printRequested() = 0; virtual void widgetChanged(RenderWidgetHostViewQtDelegate *newWidget) = 0; + virtual void interceptRequest(QWebEngineUrlRequestInfo &) { } + virtual TouchHandleDrawableClient *createTouchHandle(const QMap<int, QImage> &images) = 0; + virtual void showTouchSelectionMenu(TouchSelectionMenuController *menuController, const QRect &bounds, const QSize &handleSize) = 0; + virtual void hideTouchSelectionMenu() = 0; virtual ProfileAdapter *profileAdapter() = 0; virtual WebContentsAdapter* webContentsAdapter() = 0; diff --git a/src/core/web_contents_delegate_qt.cpp b/src/core/web_contents_delegate_qt.cpp index 20de0546f..7719e78d7 100644 --- a/src/core/web_contents_delegate_qt.cpp +++ b/src/core/web_contents_delegate_qt.cpp @@ -58,6 +58,7 @@ #include "visited_links_manager_qt.h" #include "web_contents_adapter_client.h" #include "web_contents_adapter.h" +#include "web_contents_view_qt.h" #include "web_engine_context.h" #include "web_engine_settings.h" @@ -65,7 +66,9 @@ #include "components/web_cache/browser/web_cache_manager.h" #include "content/browser/frame_host/render_frame_host_impl.h" #include "content/browser/renderer_host/render_widget_host_impl.h" +#include "content/browser/web_contents/web_contents_impl.h" #include "content/public/browser/browser_context.h" +#include "content/public/browser/file_select_listener.h" #include "content/public/browser/invalidate_type.h" #include "content/public/browser/navigation_entry.h" #include "content/public/browser/navigation_handle.h" @@ -74,7 +77,6 @@ #include "content/public/browser/render_process_host.h" #include "content/public/browser/web_contents.h" #include "content/public/common/favicon_url.h" -#include "content/public/common/file_chooser_params.h" #include "content/public/common/frame_navigate_params.h" #include "content/public/common/url_constants.h" #include "content/public/common/web_preferences.h" @@ -136,6 +138,7 @@ content::WebContents *WebContentsDelegateQt::OpenURLFromTab(content::WebContents Q_ASSERT(target); content::NavigationController::LoadURLParams load_url_params(params.url); + load_url_params.initiator_origin = params.initiator_origin; load_url_params.source_site_instance = target_site_instance; load_url_params.referrer = referrer; load_url_params.frame_tree_node_id = params.frame_tree_node_id; @@ -145,7 +148,11 @@ content::WebContents *WebContentsDelegateQt::OpenURLFromTab(content::WebContents load_url_params.should_replace_current_entry = params.should_replace_current_entry; load_url_params.is_renderer_initiated = params.is_renderer_initiated; load_url_params.started_from_context_menu = params.started_from_context_menu; + load_url_params.has_user_gesture = params.user_gesture; + load_url_params.blob_url_loader_factory = params.blob_url_loader_factory; load_url_params.override_user_agent = content::NavigationController::UA_OVERRIDE_TRUE; + load_url_params.href_translate = params.href_translate; + load_url_params.reload_type = params.reload_type; if (params.uses_post) { load_url_params.load_type = content::NavigationController::LOAD_TYPE_HTTP_POST; load_url_params.post_data = params.post_data; @@ -155,7 +162,7 @@ content::WebContents *WebContentsDelegateQt::OpenURLFromTab(content::WebContents return target; } -static bool shouldUseActualURL(const content::NavigationEntry *entry) +static bool shouldUseActualURL(content::NavigationEntry *entry) { Q_ASSERT(entry); @@ -253,11 +260,13 @@ void WebContentsDelegateQt::LoadProgressChanged(content::WebContents */*source*/ m_viewClient->loadProgressChanged(m_lastLoadProgress); } -void WebContentsDelegateQt::HandleKeyboardEvent(content::WebContents *, const content::NativeWebKeyboardEvent &event) +bool WebContentsDelegateQt::HandleKeyboardEvent(content::WebContents *, const content::NativeWebKeyboardEvent &event) { Q_ASSERT(!event.skip_in_browser); if (event.os_event) m_viewClient->unhandledKeyEvent(reinterpret_cast<QKeyEvent *>(event.os_event)); + // FIXME: ? + return true; } void WebContentsDelegateQt::RenderFrameCreated(content::RenderFrameHost *render_frame_host) @@ -437,12 +446,14 @@ void WebContentsDelegateQt::DidUpdateFaviconURL(const std::vector<content::Favic m_faviconManager->update(faviconCandidates); } -void WebContentsDelegateQt::WebContentsCreated(content::WebContents */*source_contents*/, +void WebContentsDelegateQt::WebContentsCreated(content::WebContents * /*source_contents*/, int /*opener_render_process_id*/, int /*opener_render_frame_id*/, const std::string &/*frame_name*/, - const GURL &target_url, content::WebContents */*new_contents*/) + const GURL &target_url, content::WebContents *newContents) { m_initialTargetUrl = toQt(target_url); + if (auto *view = static_cast<content::WebContentsImpl *>(newContents)->GetView()) + static_cast<WebContentsViewQt *>(view)->setFactoryClient(m_viewClient); } content::ColorChooser *WebContentsDelegateQt::OpenColorChooser(content::WebContents *source, SkColor color, const std::vector<blink::mojom::ColorSuggestionPtr> &suggestion) @@ -477,12 +488,14 @@ bool WebContentsDelegateQt::IsFullscreenForTabOrPending(const content::WebConten return m_viewClient->isFullScreenMode(); } -ASSERT_ENUMS_MATCH(FilePickerController::Open, content::FileChooserParams::Open) -ASSERT_ENUMS_MATCH(FilePickerController::OpenMultiple, content::FileChooserParams::OpenMultiple) -ASSERT_ENUMS_MATCH(FilePickerController::UploadFolder, content::FileChooserParams::UploadFolder) -ASSERT_ENUMS_MATCH(FilePickerController::Save, content::FileChooserParams::Save) +ASSERT_ENUMS_MATCH(FilePickerController::Open, blink::mojom::FileChooserParams::Mode::kOpen) +ASSERT_ENUMS_MATCH(FilePickerController::OpenMultiple, blink::mojom::FileChooserParams::Mode::kOpenMultiple) +ASSERT_ENUMS_MATCH(FilePickerController::UploadFolder, blink::mojom::FileChooserParams::Mode::kUploadFolder) +ASSERT_ENUMS_MATCH(FilePickerController::Save, blink::mojom::FileChooserParams::Mode::kSave) -void WebContentsDelegateQt::RunFileChooser(content::RenderFrameHost *frameHost, const content::FileChooserParams ¶ms) +void WebContentsDelegateQt::RunFileChooser(content::RenderFrameHost * /*frameHost*/, + std::unique_ptr<content::FileSelectListener> listener, + const blink::mojom::FileChooserParams& params) { QStringList acceptedMimeTypes; acceptedMimeTypes.reserve(params.accept_types.size()); @@ -490,7 +503,7 @@ void WebContentsDelegateQt::RunFileChooser(content::RenderFrameHost *frameHost, acceptedMimeTypes.append(toQt(*it)); m_filePickerController.reset(new FilePickerController(static_cast<FilePickerController::FileChooserMode>(params.mode), - frameHost, toQt(params.default_file_name.value()), acceptedMimeTypes)); + std::move(listener), toQt(params.default_file_name.value()), acceptedMimeTypes)); // Defer the call to not block base::MessageLoop::RunTask with modal dialogs. QTimer::singleShot(0, [this] () { @@ -609,6 +622,11 @@ void WebContentsDelegateQt::requestGeolocationPermission(const QUrl &requestingO m_viewClient->runGeolocationPermissionRequest(requestingOrigin); } +void WebContentsDelegateQt::requestUserNotificationPermission(const QUrl &requestingOrigin) +{ + m_viewClient->runUserNotificationPermissionRequest(requestingOrigin); +} + extern WebContentsAdapterClient::NavigationType pageTransitionToNavigationType(ui::PageTransition transition); void WebContentsDelegateQt::launchExternalURL(const QUrl &url, ui::PageTransition page_transition, bool is_main_frame, bool has_user_gesture) @@ -659,16 +677,18 @@ void WebContentsDelegateQt::BeforeUnloadFired(content::WebContents *tab, bool pr m_viewClient->windowCloseRejected(); } -void WebContentsDelegateQt::BeforeUnloadFired(const base::TimeTicks &proceed_time) { +void WebContentsDelegateQt::BeforeUnloadFired(bool proceed, const base::TimeTicks &proceed_time) +{ + Q_UNUSED(proceed); Q_UNUSED(proceed_time); } -bool WebContentsDelegateQt::CheckMediaAccessPermission(content::RenderFrameHost *, const GURL& security_origin, content::MediaStreamType type) +bool WebContentsDelegateQt::CheckMediaAccessPermission(content::RenderFrameHost *, const GURL& security_origin, blink::MediaStreamType type) { switch (type) { - case content::MEDIA_DEVICE_AUDIO_CAPTURE: + case blink::MEDIA_DEVICE_AUDIO_CAPTURE: return m_viewClient->profileAdapter()->checkPermission(toQt(security_origin), ProfileAdapter::AudioCapturePermission); - case content::MEDIA_DEVICE_VIDEO_CAPTURE: + case blink::MEDIA_DEVICE_VIDEO_CAPTURE: return m_viewClient->profileAdapter()->checkPermission(toQt(security_origin), ProfileAdapter::VideoCapturePermission); default: LOG(INFO) << "WebContentsDelegateQt::CheckMediaAccessPermission: " diff --git a/src/core/web_contents_delegate_qt.h b/src/core/web_contents_delegate_qt.h index b88b56dc1..9a3afebed 100644 --- a/src/core/web_contents_delegate_qt.h +++ b/src/core/web_contents_delegate_qt.h @@ -125,7 +125,7 @@ public: void AddNewContents(content::WebContents *source, std::unique_ptr<content::WebContents> new_contents, WindowOpenDisposition disposition, const gfx::Rect &initial_pos, bool user_gesture, bool *was_blocked) override; void CloseContents(content::WebContents *source) override; void LoadProgressChanged(content::WebContents* source, double progress) override; - void HandleKeyboardEvent(content::WebContents *source, const content::NativeWebKeyboardEvent &event) override; + bool HandleKeyboardEvent(content::WebContents *source, const content::NativeWebKeyboardEvent &event) override; content::ColorChooser* OpenColorChooser(content::WebContents *source, SkColor color, const std::vector<blink::mojom::ColorSuggestionPtr> &suggestions) override; void WebContentsCreated(content::WebContents *source_contents, int opener_render_process_id, int opener_render_frame_id, const std::string &frame_name, const GURL &target_url, content::WebContents *new_contents) override; @@ -133,7 +133,9 @@ public: void EnterFullscreenModeForTab(content::WebContents *web_contents, const GURL &origin, const blink::WebFullscreenOptions &) override; void ExitFullscreenModeForTab(content::WebContents*) override; bool IsFullscreenForTabOrPending(const content::WebContents* web_contents) const override; - void RunFileChooser(content::RenderFrameHost* render_frame_host, const content::FileChooserParams& params) override; + void RunFileChooser(content::RenderFrameHost* render_frame_host, + std::unique_ptr<content::FileSelectListener> listener, + const blink::mojom::FileChooserParams& params) override; bool DidAddMessageToConsole(content::WebContents* source, int32_t level, const base::string16& message, int32_t line_no, const base::string16& source_id) override; void FindReply(content::WebContents *source, int request_id, int number_of_matches, const gfx::Rect& selection_rect, int active_match_ordinal, bool final_update) override; void RequestMediaAccessPermission(content::WebContents *web_contents, @@ -143,7 +145,7 @@ 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, content::MediaStreamType type) override; + bool CheckMediaAccessPermission(content::RenderFrameHost* render_frame_host, const GURL& security_origin, blink::MediaStreamType type) override; void RegisterProtocolHandler(content::WebContents* web_contents, const std::string& protocol, const GURL& url, bool user_gesture) override; void UnregisterProtocolHandler(content::WebContents* web_contents, const std::string& protocol, const GURL& url, bool user_gesture) override; bool TakeFocus(content::WebContents *source, bool reverse) override; @@ -157,7 +159,7 @@ public: void DidFinishNavigation(content::NavigationHandle *navigation_handle) override; void DidFailLoad(content::RenderFrameHost* render_frame_host, const GURL& validated_url, int error_code, const base::string16& error_description) override; void DidFinishLoad(content::RenderFrameHost *render_frame_host, const GURL &validated_url) override; - void BeforeUnloadFired(const base::TimeTicks& proceed_time) override; + void BeforeUnloadFired(bool proceed, const base::TimeTicks& proceed_time) override; void DidUpdateFaviconURL(const std::vector<content::FaviconURL> &candidates) override; void OnVisibilityChanged(content::Visibility visibility) override; void DidFirstVisuallyNonEmptyPaint() override; @@ -168,6 +170,7 @@ public: void allowCertificateError(const QSharedPointer<CertificateErrorController> &); void selectClientCert(const QSharedPointer<ClientCertSelectController> &); void requestGeolocationPermission(const QUrl &requestingOrigin); + void requestUserNotificationPermission(const QUrl &requestingOrigin); void launchExternalURL(const QUrl &url, ui::PageTransition page_transition, bool is_main_frame, bool has_user_gesture); FaviconManager *faviconManager(); diff --git a/src/core/web_contents_view_qt.cpp b/src/core/web_contents_view_qt.cpp index 7e0275aa0..ef7c09665 100644 --- a/src/core/web_contents_view_qt.cpp +++ b/src/core/web_contents_view_qt.cpp @@ -41,11 +41,15 @@ #include "profile_adapter.h" #include "content_browser_client_qt.h" +#include "render_widget_host_view_qt.h" #include "render_widget_host_view_qt_delegate.h" #include "render_widget_host_view_qt.h" +#include "touch_selection_controller_client_qt.h" #include "type_conversion.h" +#include "web_contents_adapter_client.h" #include "web_contents_adapter.h" #include "web_engine_context.h" +#include "web_contents_delegate_qt.h" #include "components/spellcheck/spellcheck_buildflags.h" #include "content/browser/renderer_host/render_view_host_impl.h" @@ -53,13 +57,25 @@ #include "content/browser/web_contents/web_contents_impl.h" #include "content/public/browser/web_contents_delegate.h" #include "content/public/common/context_menu_params.h" -#include <ui/gfx/image/image_skia.h> +#include "ui/gfx/image/image_skia.h" #include <QtGui/qpixmap.h> namespace QtWebEngineCore { -void WebContentsViewQt::initialize(WebContentsAdapterClient* client) +void WebContentsViewQt::setFactoryClient(WebContentsAdapterClient* client) +{ + if (m_factoryClient) + return; + m_factoryClient = client; + + // Check if a RWHV was created before the pre-initialization. + if (auto view = static_cast<RenderWidgetHostViewQt *>(m_webContents->GetRenderWidgetHostView())) { + view->setDelegate(m_factoryClient->CreateRenderWidgetHostViewQtDelegate(view)); + } +} + +void WebContentsViewQt::setClient(WebContentsAdapterClient* client) { m_client = client; m_factoryClient = client; @@ -75,15 +91,16 @@ content::RenderWidgetHostViewBase* WebContentsViewQt::CreateViewForWidget(conten { RenderWidgetHostViewQt *view = new RenderWidgetHostViewQt(render_widget_host); - Q_ASSERT(m_factoryClient); - view->setDelegate(m_factoryClient->CreateRenderWidgetHostViewQtDelegate(view)); - if (m_client) - view->setAdapterClient(m_client); + if (m_factoryClient) { + view->setDelegate(m_factoryClient->CreateRenderWidgetHostViewQtDelegate(view)); + if (m_client) + view->setAdapterClient(m_client); + } return view; } -content::RenderWidgetHostViewBase* WebContentsViewQt::CreateViewForPopupWidget(content::RenderWidgetHost* render_widget_host) +content::RenderWidgetHostViewBase* WebContentsViewQt::CreateViewForChildWidget(content::RenderWidgetHost* render_widget_host) { RenderWidgetHostViewQt *view = new RenderWidgetHostViewQt(render_widget_host); @@ -96,15 +113,11 @@ content::RenderWidgetHostViewBase* WebContentsViewQt::CreateViewForPopupWidget(c void WebContentsViewQt::CreateView(const gfx::Size& initial_size, gfx::NativeView context) { - // This is passed through content::WebContents::CreateParams::context either as the native view's client - // directly or, in the case of a page-created new window, the client of the creating window's native view. - m_factoryClient = reinterpret_cast<WebContentsAdapterClient *>(context); } gfx::NativeView WebContentsViewQt::GetNativeView() const { - // Hack to provide the client to WebContentsImpl::CreateNewWindow. - return reinterpret_cast<gfx::NativeView>(m_client); + return nullptr; } void WebContentsViewQt::GetContainerBounds(gfx::Rect* out) const @@ -203,6 +216,11 @@ static inline WebEngineContextMenuData fromParams(const content::ContextMenuPara void WebContentsViewQt::ShowContextMenu(content::RenderFrameHost *, const content::ContextMenuParams ¶ms) { + if (auto rwhv = static_cast<RenderWidgetHostViewQt *>(m_webContents->GetRenderWidgetHostView())) { + if (rwhv && rwhv->getTouchSelectionControllerClient()->handleContextMenu(params)) + return; + } + WebEngineContextMenuData contextMenuData(fromParams(params)); #if QT_CONFIG(webengine_spellchecker) // Do not use params.spellcheck_enabled, since it is never @@ -247,7 +265,7 @@ void WebContentsViewQt::StartDragging(const content::DropData &drop_data, QPixmap pixmap; QPoint hotspot; - pixmap = QPixmap::fromImage(toQImage(image.GetRepresentation(m_client->dpiScale()))); + pixmap = QPixmap::fromImage(toQImage(image.GetRepresentation(1.0))); if (!pixmap.isNull()) { hotspot.setX(image_offset.x()); hotspot.setY(image_offset.y()); diff --git a/src/core/web_contents_view_qt.h b/src/core/web_contents_view_qt.h index 7036907c5..ec09f9aae 100644 --- a/src/core/web_contents_view_qt.h +++ b/src/core/web_contents_view_qt.h @@ -63,10 +63,10 @@ public: : m_webContents(webContents) , m_client(nullptr) , m_factoryClient(nullptr) - , m_allowOtherViews(false) { } - void initialize(WebContentsAdapterClient* client); + void setFactoryClient(WebContentsAdapterClient* client); + void setClient(WebContentsAdapterClient* client); WebContentsAdapterClient *client() { return m_client; } // content::WebContentsView overrides: @@ -74,7 +74,7 @@ public: void CreateView(const gfx::Size& initial_size, gfx::NativeView context) override; - content::RenderWidgetHostViewBase* CreateViewForPopupWidget(content::RenderWidgetHost* render_widget_host) override; + content::RenderWidgetHostViewBase *CreateViewForChildWidget(content::RenderWidgetHost* render_widget_host) override; void SetPageTitle(const base::string16& title) override { } @@ -84,35 +84,33 @@ public: void RenderViewHostChanged(content::RenderViewHost*, content::RenderViewHost*) override { } - void SetOverscrollControllerEnabled(bool enabled) override { QT_NOT_YET_IMPLEMENTED } + void SetOverscrollControllerEnabled(bool enabled) override { } gfx::NativeView GetNativeView() const override; - gfx::NativeView GetContentNativeView() const override { QT_NOT_USED return 0; } + gfx::NativeView GetContentNativeView() const override { return nullptr; } - gfx::NativeWindow GetTopLevelNativeWindow() const override { QT_NOT_USED return 0; } + gfx::NativeWindow GetTopLevelNativeWindow() const override { return nullptr; } void GetContainerBounds(gfx::Rect* out) const override; - void SizeContents(const gfx::Size& size) override { QT_NOT_YET_IMPLEMENTED } + void SizeContents(const gfx::Size& size) override { } void Focus() override; void SetInitialFocus() override; - void StoreFocus() override { QT_NOT_USED } + void StoreFocus() override { } - void RestoreFocus() override { QT_NOT_USED } + void RestoreFocus() override { } content::DropData* GetDropData() const override { QT_NOT_YET_IMPLEMENTED return nullptr; } - gfx::Rect GetViewBounds() const override { QT_NOT_YET_IMPLEMENTED return gfx::Rect(); } + gfx::Rect GetViewBounds() const override { return gfx::Rect(); } void FocusThroughTabTraversal(bool reverse) override; #if defined(OS_MACOSX) - void SetAllowOtherViews(bool allow) override { m_allowOtherViews = allow; } - bool GetAllowOtherViews() const override { return m_allowOtherViews; } void CloseTabAfterEventTracking() override { QT_NOT_YET_IMPLEMENTED } bool IsEventTracking() const override { QT_NOT_YET_IMPLEMENTED; return false; } #endif // defined(OS_MACOSX) @@ -135,7 +133,6 @@ private: content::WebContents *m_webContents; WebContentsAdapterClient *m_client; WebContentsAdapterClient *m_factoryClient; - bool m_allowOtherViews; }; } // namespace QtWebEngineCore diff --git a/src/core/web_engine_context.cpp b/src/core/web_engine_context.cpp index 4af486456..a3a5881bf 100644 --- a/src/core/web_engine_context.cpp +++ b/src/core/web_engine_context.cpp @@ -44,23 +44,25 @@ #include "base/base_switches.h" #include "base/command_line.h" #include "base/files/file_path.h" -#include "base/message_loop/message_loop.h" +#include "base/message_loop/message_loop_impl.h" #include "base/run_loop.h" +#include "base/task/post_task.h" #include "base/threading/thread_restrictions.h" #include "cc/base/switches.h" #if QT_CONFIG(webengine_printing_and_pdf) #include "chrome/browser/printing/print_job_manager.h" +#include "components/printing/browser/features.h" #endif #include "components/viz/common/features.h" #include "components/web_cache/browser/web_cache_manager.h" #include "content/browser/devtools/devtools_http_handler.h" -#include "content/browser/gpu/gpu_main_thread_factory.h" -#include "content/browser/renderer_host/render_process_host_impl.h" -#include "content/browser/utility_process_host.h" -#include "content/gpu/in_process_gpu_thread.h" +#include "content/browser/scheduler/browser_task_executor.h" +#include "content/browser/startup_helper.h" #include "content/public/app/content_main.h" #include "content/public/app/content_main_runner.h" #include "content/public/browser/browser_main_runner.h" +#include "content/public/browser/browser_task_traits.h" +#include "content/public/browser/browser_thread.h" #include "content/public/browser/plugin_service.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_process_host.h" @@ -68,17 +70,16 @@ #include "content/public/common/content_paths.h" #include "content/public/common/content_switches.h" #include "content/public/common/main_function_params.h" -#include "content/renderer/in_process_renderer_thread.h" -#include "content/utility/in_process_utility_thread.h" #include "gpu/command_buffer/service/gpu_switches.h" +#include "gpu/command_buffer/service/sync_point_manager.h" #include "gpu/ipc/host/gpu_switches.h" #include "media/audio/audio_manager.h" -#include "media/base/media_switches.h" #include "mojo/core/embedder/embedder.h" #include "net/base/port_util.h" #include "ppapi/buildflags/buildflags.h" -#include "services/service_manager/sandbox/switches.h" +#include "services/network/public/cpp/network_switches.h" #include "services/resource_coordinator/public/cpp/resource_coordinator_features.h" +#include "services/service_manager/sandbox/switches.h" #include "ui/events/event_switches.h" #include "ui/native_theme/native_theme_features.h" #include "ui/gl/gl_switches.h" @@ -87,20 +88,24 @@ #include "content/public/app/sandbox_helper_win.h" #endif // OS_WIN +#ifndef QT_NO_ACCESSIBILITY +#include "accessibility_activation_observer.h" +#endif #include "api/qwebengineurlscheme.h" -#include "profile_adapter.h" #include "content_browser_client_qt.h" #include "content_client_qt.h" #include "content_main_delegate_qt.h" #include "devtools_manager_delegate_qt.h" #include "media_capture_devices_dispatcher.h" #include "net/webui_controller_factory_qt.h" -#include "type_conversion.h" #include "ozone/gl_context_qt.h" +#include "profile_adapter.h" +#include "type_conversion.h" #include "web_engine_library_info.h" #include <QFileInfo> #include <QGuiApplication> +#include <QMutex> #include <QOffscreenSurface> #ifndef QT_NO_OPENGL # include <QOpenGLContext> @@ -109,7 +114,9 @@ #include <QStringList> #include <QSurfaceFormat> #include <QVector> -#include <qpa/qplatformnativeinterface.h> +#include <QNetworkProxy> +#include <QtGui/qpa/qplatformintegration.h> +#include <QtGui/private/qguiapplication_p.h> using namespace QtWebEngineCore; @@ -133,10 +140,13 @@ bool usingANGLE() #endif } -bool usingQtQuick2DRenderer() +bool usingDefaultSGBackend() { const QStringList args = QGuiApplication::arguments(); - QString device; + + //folow logic from contextFactory in src/quick/scenegraph/qsgcontextplugin.cpp + QString device = QQuickWindow::sceneGraphBackend(); + for (int index = 0; index < args.count(); ++index) { if (args.at(index).startsWith(QLatin1String("--device="))) { device = args.at(index).mid(9); @@ -145,16 +155,11 @@ bool usingQtQuick2DRenderer() } if (device.isEmpty()) - device = QQuickWindow::sceneGraphBackend(); - if (device.isEmpty()) device = QString::fromLocal8Bit(qgetenv("QT_QUICK_BACKEND")); if (device.isEmpty()) device = QString::fromLocal8Bit(qgetenv("QMLSCENE_DEVICE")); - if (device.isEmpty()) - device = QLatin1String("default"); - // Anything other than the default OpenGL device will need to render in 2D mode. - return device != QLatin1String("default"); + return device.isEmpty(); } #endif //QT_NO_OPENGL #if QT_CONFIG(webengine_pepper_plugins) @@ -167,6 +172,8 @@ void dummyGetPluginCallback(const std::vector<content::WebPluginInfo>&) namespace QtWebEngineCore { +extern std::unique_ptr<base::MessagePump> messagePumpFactory(); + bool usingSoftwareDynamicGL() { if (QCoreApplication::testAttribute(Qt::AA_UseSoftwareOpenGL)) @@ -189,9 +196,9 @@ void WebEngineContext::destroyProfileAdapter() { if (content::RenderProcessHost::run_renderer_in_process()) { Q_ASSERT(m_profileAdapters.count() == 1); - // this might be default profile - m_defaultProfileAdapter.release(); - delete m_profileAdapters.first(); + // this is a default profile + m_defaultProfileAdapter.reset(); + Q_ASSERT(m_profileAdapters.isEmpty()); } } @@ -209,9 +216,11 @@ void WebEngineContext::addProfileAdapter(ProfileAdapter *profileAdapter) } } - if (content::RenderProcessHost::run_renderer_in_process() && - !m_profileAdapters.isEmpty()) { - qFatal("Single mode supports only single profile."); + if (content::RenderProcessHost::run_renderer_in_process()){ + if (!m_profileAdapters.isEmpty()) + qFatal("Single mode supports only single profile."); + // there is only one profle therefore make it 'default' + m_defaultProfileAdapter.reset(profileAdapter); } m_profileAdapters.append(profileAdapter); } @@ -225,8 +234,14 @@ void WebEngineContext::destroy() { if (m_devtoolsServer) m_devtoolsServer->stop(); + + // 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. + destroyGpuProcess(); + base::MessagePump::Delegate *delegate = - static_cast<base::MessageLoop *>(m_runLoop->delegate_); + static_cast<base::MessageLoopImpl *>(m_runLoop->delegate_); // Flush the UI message loop before quitting. while (delegate->DoWork()) { } @@ -274,6 +289,7 @@ WebEngineContext::~WebEngineContext() Q_ASSERT(!m_devtoolsServer); Q_ASSERT(!m_browserRunner); Q_ASSERT(m_profileAdapters.isEmpty()); + delete s_syncPointManager.fetchAndStoreRelaxed(nullptr); } WebEngineContext *WebEngineContext::current() @@ -293,8 +309,13 @@ WebEngineContext *WebEngineContext::current() ProfileAdapter *WebEngineContext::createDefaultProfileAdapter() { Q_ASSERT(!m_destroyed); - if (!m_defaultProfileAdapter) - m_defaultProfileAdapter.reset(new ProfileAdapter(QStringLiteral("Default"))); + if (!m_defaultProfileAdapter) { + ProfileAdapter *profile = new ProfileAdapter(QStringLiteral("Default")); + // profile when added to m_profileAdapters might be set default + // profile in case of single-process + if (!m_defaultProfileAdapter) + m_defaultProfileAdapter.reset(profile); + } return m_defaultProfileAdapter.get(); } @@ -313,7 +334,7 @@ void WebEngineContext::destroyContextPostRoutine() // Destroy WebEngineContext before its static pointer is zeroed and destructor called. // Before destroying MessageLoop via destroying BrowserMainRunner destructor // WebEngineContext's pointer is used. - m_handle->destroy(); + m_handle->destroy(); #if !defined(NDEBUG) if (!m_handle->HasOneRef()) qWarning("WebEngineContext leaked on exit, likely due to leaked WebEngine View or Page"); @@ -322,6 +343,18 @@ void WebEngineContext::destroyContextPostRoutine() m_destroyed = true; } +ProxyAuthentication WebEngineContext::qProxyNetworkAuthentication(QString host, int port) +{ + if (!QNetworkProxyFactory::usesSystemConfiguration()) { + QNetworkProxy proxy = QNetworkProxy::applicationProxy(); + if (host == proxy.hostName() && port == proxy.port() && !proxy.user().isEmpty() + && !proxy.password().isEmpty()) { + return std::make_tuple(true, proxy.user(), proxy.password()); + } + } + return std::make_tuple(false, QString(), QString()); +} + #ifndef CHROMIUM_VERSION #error Chromium version should be defined at gyp-time. Something must have gone wrong #define CHROMIUM_VERSION // This is solely to keep Qt Creator happy. @@ -330,7 +363,15 @@ void WebEngineContext::destroyContextPostRoutine() const static char kChromiumFlagsEnv[] = "QTWEBENGINE_CHROMIUM_FLAGS"; const static char kDisableSandboxEnv[] = "QTWEBENGINE_DISABLE_SANDBOX"; -static void appendToFeatureSwitch(base::CommandLine *commandLine, const char *featureSwitch, const char *feature) +static void appendToFeatureList(std::string &featureList, const char *feature) +{ + if (featureList.empty()) + featureList = feature; + else + featureList = featureList + "," + feature; +} + +static void appendToFeatureSwitch(base::CommandLine *commandLine, const char *featureSwitch, std::string feature) { if (!commandLine->HasSwitch(featureSwitch)) { commandLine->AppendSwitchASCII(featureSwitch, feature); @@ -347,7 +388,8 @@ WebEngineContext::WebEngineContext() { base::TaskScheduler::Create("Browser"); m_contentRunner.reset(content::ContentMainRunner::Create()); - m_browserRunner.reset(content::BrowserMainRunner::Create()); + m_browserRunner = content::BrowserMainRunner::Create(); + #ifdef Q_OS_LINUX // Call qputenv before BrowserMainRunnerImpl::Initialize is called. // http://crbug.com/245466 @@ -366,35 +408,24 @@ WebEngineContext::WebEngineContext() QWebEngineUrlScheme::lockSchemes(); // Allow us to inject javascript like any webview toolkit. - content::RenderFrameHost::AllowInjectingJavaScriptForAndroidWebView(); + content::RenderFrameHost::AllowInjectingJavaScript(); - base::CommandLine::CreateEmpty(); - base::CommandLine* parsedCommandLine = base::CommandLine::ForCurrentProcess(); QStringList appArgs = QCoreApplication::arguments(); - if (qEnvironmentVariableIsSet(kChromiumFlagsEnv)) { - appArgs = appArgs.mid(0, 1); // Take application name and drop the rest - appArgs.append(QString::fromLocal8Bit(qgetenv(kChromiumFlagsEnv)).split(' ')); - } - bool enableWebGLSoftwareRendering = - appArgs.removeAll(QStringLiteral("--enable-webgl-software-rendering")); + // If user requested GL support instead of using Skia rendering to + // bitmaps, use software rendering via software OpenGL. This might be less + // performant, but at least provides WebGL support. + // TODO(miklocek), check if this still works with latest chromium + bool enableGLSoftwareRendering = appArgs.contains(QStringLiteral("--enable-webgl-software-rendering")); bool useEmbeddedSwitches = false; #if defined(QTWEBENGINE_EMBEDDED_SWITCHES) - useEmbeddedSwitches = !appArgs.removeAll(QStringLiteral("--disable-embedded-switches")); -#else - useEmbeddedSwitches = appArgs.removeAll(QStringLiteral("--enable-embedded-switches")); -#endif - base::CommandLine::StringVector argv; - argv.resize(appArgs.size()); -#if defined(Q_OS_WIN) - for (int i = 0; i < appArgs.size(); ++i) - argv[i] = toString16(appArgs[i]); + useEmbeddedSwitches = !appArgs.contains(QStringLiteral("--disable-embedded-switches")); #else - for (int i = 0; i < appArgs.size(); ++i) - argv[i] = appArgs[i].toStdString(); + useEmbeddedSwitches = appArgs.contains(QStringLiteral("--enable-embedded-switches")); #endif - parsedCommandLine->InitFromArgv(argv); + + base::CommandLine* parsedCommandLine = commandLine(); parsedCommandLine->AppendSwitchPath(switches::kBrowserSubprocessPath, WebEngineLibraryInfo::getPath(content::CHILD_PROCESS_EXE)); @@ -427,8 +458,6 @@ WebEngineContext::WebEngineContext() parsedCommandLine->AppendSwitch(switches::kDisablePepper3DImageChromium); // Same problem with select popups. parsedCommandLine->AppendSwitch(switches::kDisableNativeGpuMemoryBuffers); - // SandboxV2 doesn't currently work for us - appendToFeatureSwitch(parsedCommandLine, switches::kDisableFeatures, features::kMacV2Sandbox.name); #endif #if defined(Q_OS_WIN) @@ -436,35 +465,59 @@ WebEngineContext::WebEngineContext() // an OpenGL Core Profile context. If the switch is not set, it would always try to create a // Core Profile context, even if Qt uses a legacy profile, which causes // "Could not share GL contexts" warnings, because it's not possible to share between Core and - // legacy profiles. - // Given that Core profile is not currently supported on Windows anyway, pass this switch to - // get rid of the warnings. - parsedCommandLine->AppendSwitch(switches::kDisableES3GLContext); + // legacy profiles. See GLContextWGL::Initialize(). + // Given that Desktop GL Core profile is not currently supported on Windows anyway, pass this + // switch to get rid of the warnings. + // + // The switch is also used to determine which version of OpenGL ES to use (2 or 3) when using + // ANGLE. + // If the switch is not set, Chromium will always try to create an ES3 context, even if Qt uses + // an ES2 context, which causes resource sharing issues (black screen), + // see gpu::gles2::GenerateGLContextAttribs(). + // Make sure to disable ES3 context creation when using ES2. + const bool isGLES2Context = qt_gl_global_share_context() + && qt_gl_global_share_context()->isOpenGLES() + && qt_gl_global_share_context()->format().majorVersion() == 2; + const bool isDesktopGLOrSoftware = !usingANGLE(); + + if (isDesktopGLOrSoftware || isGLES2Context) + parsedCommandLine->AppendSwitch(switches::kDisableES3GLContext); #endif + + std::string disableFeatures; + std::string enableFeatures; // Needed to allow navigations within pages that were set using setHtml(). One example is // tst_QWebEnginePage::acceptNavigationRequest. // This is deprecated behavior, and will be removed in a future Chromium version, as per // upstream Chromium commit ba52f56207a4b9d70b34880fbff2352e71a06422. - appendToFeatureSwitch(parsedCommandLine, switches::kEnableFeatures, features::kAllowContentInitiatedDataUrlNavigations.name); + appendToFeatureList(enableFeatures, features::kAllowContentInitiatedDataUrlNavigations.name); // Surface synchronization breaks our current graphics integration (since 65) - appendToFeatureSwitch(parsedCommandLine, switches::kDisableFeatures, features::kEnableSurfaceSynchronization.name); + appendToFeatureList(disableFeatures, features::kEnableSurfaceSynchronization.name); + // Viz Display Compositor is enabled by default since 73. Doesn't work for us (also implies SurfaceSynchronization) + appendToFeatureList(disableFeatures, features::kVizDisplayCompositor.name); // The video-capture service is not functioning at this moment (since 69) - appendToFeatureSwitch(parsedCommandLine, switches::kDisableFeatures, features::kMojoVideoCapture.name); - // We do not yet support the internal video capture API. - appendToFeatureSwitch(parsedCommandLine, switches::kDisableFeatures, features::kUseVideoCaptureApiForDevToolsSnapshots.name); - // Qt 5.12 only: The modern media controls are not yet good enough in 69-based, - // so we stick to the old style - appendToFeatureSwitch(parsedCommandLine, switches::kDisableFeatures, media::kUseModernMediaControls.name); + appendToFeatureList(disableFeatures, features::kMojoVideoCapture.name); + // Breaks WebEngineNewViewRequest.userInitiated API (since 73) + appendToFeatureList(disableFeatures, features::kUserActivationV2.name); + + appendToFeatureList(disableFeatures, features::kBackgroundFetch.name); + +#if QT_CONFIG(webengine_printing_and_pdf) + appendToFeatureList(disableFeatures, printing::features::kUsePdfCompositorServiceForPrint.name); +#endif if (useEmbeddedSwitches) { // embedded switches are based on the switches for Android, see content/browser/android/content_startup_flags.cc - appendToFeatureSwitch(parsedCommandLine, switches::kEnableFeatures, features::kOverlayScrollbar.name); + appendToFeatureList(enableFeatures, features::kOverlayScrollbar.name); if (!parsedCommandLine->HasSwitch(switches::kDisablePinch)) parsedCommandLine->AppendSwitch(switches::kEnablePinch); parsedCommandLine->AppendSwitch(switches::kEnableViewport); parsedCommandLine->AppendSwitch(switches::kMainFrameResizesAreOrientationChanges); parsedCommandLine->AppendSwitch(cc::switches::kDisableCompositedAntialiasing); } + + appendToFeatureSwitch(parsedCommandLine, switches::kDisableFeatures, disableFeatures); + appendToFeatureSwitch(parsedCommandLine, switches::kEnableFeatures, enableFeatures); base::FeatureList::InitializeInstance( parsedCommandLine->GetSwitchValueASCII(switches::kEnableFeatures), parsedCommandLine->GetSwitchValueASCII(switches::kDisableFeatures)); @@ -474,22 +527,18 @@ WebEngineContext::WebEngineContext() const char *glType = 0; #ifndef QT_NO_OPENGL - bool tryGL = - !usingANGLE() - && (!usingSoftwareDynamicGL() - // If user requested WebGL support instead of using Skia rendering to - // bitmaps, use software rendering via software OpenGL. This might be less - // performant, but at least provides WebGL support. - || enableWebGLSoftwareRendering - ) - && !usingQtQuick2DRenderer(); - + const bool tryGL = (usingDefaultSGBackend() && !usingSoftwareDynamicGL() && + QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL)) + || enableGLSoftwareRendering; if (tryGL) { if (qt_gl_global_share_context() && qt_gl_global_share_context()->isValid()) { - // If the native handle is QEGLNativeContext try to use GL ES/2, if there is no native handle - // assume we are using wayland and try GL ES/2, and finally Ozone demands GL ES/2 too. + // If the native handle is QEGLNativeContext try to use GL ES/2. + // If there is no native handle, assume we are using wayland and try GL ES/2. + // If we are using ANGLE on Windows, use OpenGL ES (2 or 3). if (qt_gl_global_share_context()->nativeHandle().isNull() - || !strcmp(qt_gl_global_share_context()->nativeHandle().typeName(), "QEGLNativeContext")) + || !strcmp(qt_gl_global_share_context()->nativeHandle().typeName(), + "QEGLNativeContext") + || usingANGLE()) { if (qt_gl_global_share_context()->isOpenGLES()) { glType = gl::kGLImplementationEGLName; @@ -547,7 +596,7 @@ WebEngineContext::WebEngineContext() if (glType) { parsedCommandLine->AppendSwitchASCII(switches::kUseGL, glType); parsedCommandLine->AppendSwitch(switches::kInProcessGPU); - if (enableWebGLSoftwareRendering) { + if (enableGLSoftwareRendering) { parsedCommandLine->AppendSwitch(switches::kDisableGpuRasterization); parsedCommandLine->AppendSwitch(switches::kIgnoreGpuBlacklist); } @@ -555,9 +604,16 @@ WebEngineContext::WebEngineContext() parsedCommandLine->AppendSwitch(switches::kDisableGpu); } - content::UtilityProcessHost::RegisterUtilityMainThreadFactory(content::CreateInProcessUtilityThread); - content::RenderProcessHostImpl::RegisterRendererMainThreadFactory(content::CreateInProcessRendererThread); - content::RegisterGpuMainThreadFactory(content::CreateInProcessGpuThread); + bool threadedGpu = true; +#ifndef QT_NO_OPENGL + threadedGpu = QOpenGLContext::supportsThreadedOpenGL(); +#endif + registerMainThreadFactories(threadedGpu); + + SetContentClient(new ContentClientQt); + + content::StartBrowserTaskScheduler(); + content::BrowserTaskExecutor::Create(); mojo::core::Init(); @@ -586,8 +642,8 @@ WebEngineContext::WebEngineContext() base::ThreadRestrictions::SetIOAllowed(true); - if (parsedCommandLine->HasSwitch(switches::kExplicitlyAllowedPorts)) { - std::string allowedPorts = parsedCommandLine->GetSwitchValueASCII(switches::kExplicitlyAllowedPorts); + if (parsedCommandLine->HasSwitch(network::switches::kExplicitlyAllowedPorts)) { + std::string allowedPorts = parsedCommandLine->GetSwitchValueASCII(network::switches::kExplicitlyAllowedPorts); net::SetExplicitlyAllowedPorts(allowedPorts); } @@ -609,6 +665,10 @@ WebEngineContext::WebEngineContext() m_printJobManager.reset(new printing::PrintJobManager()); #endif +#ifndef QT_NO_ACCESSIBILITY + m_accessibilityActivationObserver.reset(new AccessibilityActivationObserver()); +#endif + content::WebUIControllerFactory::RegisterFactory(WebUIControllerFactoryQt::GetInstance()); } @@ -618,4 +678,48 @@ printing::PrintJobManager* WebEngineContext::getPrintJobManager() return m_printJobManager.get(); } #endif + +static QMutex s_spmMutex; +QAtomicPointer<gpu::SyncPointManager> WebEngineContext::s_syncPointManager; + +gpu::SyncPointManager *WebEngineContext::syncPointManager() +{ + if (gpu::SyncPointManager *spm = s_syncPointManager.loadAcquire()) + return spm; + QMutexLocker lock(&s_spmMutex); + if (!s_syncPointManager) + s_syncPointManager.store(new gpu::SyncPointManager()); + return s_syncPointManager.load(); +} + +base::CommandLine* WebEngineContext::commandLine() { + if (base::CommandLine::CreateEmpty()) { + base::CommandLine* parsedCommandLine = base::CommandLine::ForCurrentProcess(); + QStringList appArgs = QCoreApplication::arguments(); + if (qEnvironmentVariableIsSet(kChromiumFlagsEnv)) { + appArgs = appArgs.mid(0, 1); // Take application name and drop the rest + appArgs.append(QString::fromLocal8Bit(qgetenv(kChromiumFlagsEnv)).split(' ')); + } +#ifdef Q_OS_WIN + appArgs.removeAll(QStringLiteral("--enable-webgl-software-rendering")); +#endif + appArgs.removeAll(QStringLiteral("--disable-embedded-switches")); + appArgs.removeAll(QStringLiteral("--enable-embedded-switches")); + + base::CommandLine::StringVector argv; + argv.resize(appArgs.size()); +#if defined(Q_OS_WIN) + for (int i = 0; i < appArgs.size(); ++i) + argv[i] = toString16(appArgs[i]); +#else + for (int i = 0; i < appArgs.size(); ++i) + argv[i] = appArgs[i].toStdString(); +#endif + parsedCommandLine->InitFromArgv(argv); + return parsedCommandLine; + } else { + return base::CommandLine::ForCurrentProcess(); + } +} + } // namespace diff --git a/src/core/web_engine_context.h b/src/core/web_engine_context.h index 604c85a61..2364bacbe 100644 --- a/src/core/web_engine_context.h +++ b/src/core/web_engine_context.h @@ -47,11 +47,20 @@ namespace base { class RunLoop; +class CommandLine; } namespace content { class BrowserMainRunner; class ContentMainRunner; +class GpuProcess; +class GpuThreadController; +class InProcessChildThreadParams; +} + +namespace gpu { +struct GpuPreferences; +class SyncPointManager; } #if QT_CONFIG(webengine_printing_and_pdf) @@ -64,16 +73,20 @@ QT_FORWARD_DECLARE_CLASS(QObject) namespace QtWebEngineCore { -class ProfileAdapter; +class AccessibilityActivationObserver; class ContentMainDelegateQt; class DevToolsServerQt; +class ProfileAdapter; bool usingSoftwareDynamicGL(); +typedef std::tuple<bool, QString, QString> ProxyAuthentication; + class WebEngineContext : public base::RefCounted<WebEngineContext> { public: static WebEngineContext *current(); static void destroyContextPostRoutine(); + static ProxyAuthentication qProxyNetworkAuthentication(QString host, int port); ProfileAdapter *createDefaultProfileAdapter(); ProfileAdapter *defaultProfileAdapter(); @@ -86,6 +99,9 @@ public: void addProfileAdapter(ProfileAdapter *profileAdapter); void removeProfileAdapter(ProfileAdapter *profileAdapter); void destroy(); + static base::CommandLine* commandLine(); + + static gpu::SyncPointManager *syncPointManager(); private: friend class base::RefCounted<WebEngineContext>; @@ -93,6 +109,9 @@ private: WebEngineContext(); ~WebEngineContext(); + static void registerMainThreadFactories(bool threaded); + static void destroyGpuProcess(); + std::unique_ptr<base::RunLoop> m_runLoop; std::unique_ptr<ContentMainDelegateQt> m_mainDelegate; std::unique_ptr<content::ContentMainRunner> m_contentRunner; @@ -101,12 +120,16 @@ private: std::unique_ptr<ProfileAdapter> m_defaultProfileAdapter; std::unique_ptr<DevToolsServerQt> m_devtoolsServer; QVector<ProfileAdapter*> m_profileAdapters; +#ifndef QT_NO_ACCESSIBILITY + std::unique_ptr<AccessibilityActivationObserver> m_accessibilityActivationObserver; +#endif #if QT_CONFIG(webengine_printing_and_pdf) std::unique_ptr<printing::PrintJobManager> m_printJobManager; #endif static scoped_refptr<QtWebEngineCore::WebEngineContext> m_handle; static bool m_destroyed; + static QAtomicPointer<gpu::SyncPointManager> s_syncPointManager; }; } // namespace diff --git a/src/core/web_engine_context_threads.cpp b/src/core/web_engine_context_threads.cpp new file mode 100644 index 000000000..e92cf3e9b --- /dev/null +++ b/src/core/web_engine_context_threads.cpp @@ -0,0 +1,136 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "web_engine_context.h" + +#include "base/bind.h" +#include "base/task/post_task.h" +#include "base/threading/platform_thread.h" +#include "base/threading/thread_restrictions.h" +#include "content/browser/gpu/gpu_main_thread_factory.h" +#include "content/browser/renderer_host/render_process_host_impl.h" +#include "content/browser/utility_process_host.h" +#include "content/gpu/gpu_child_thread.h" +#include "content/gpu/gpu_process.h" +#include "content/gpu/in_process_gpu_thread.h" +#include "content/public/browser/browser_task_traits.h" +#include "content/public/browser/browser_thread.h" +#include "content/renderer/in_process_renderer_thread.h" +#include "content/utility/in_process_utility_thread.h" +#include "gpu/ipc/service/gpu_init.h" + +#include <memory> + +namespace QtWebEngineCore { + +struct GpuThreadControllerQt : content::GpuThreadController +{ + GpuThreadControllerQt(const content::InProcessChildThreadParams ¶ms, const gpu::GpuPreferences &gpuPreferences) + { + base::PostTaskWithTraits( + FROM_HERE, { content::BrowserThread::UI }, + base::BindOnce(&GpuThreadControllerQt::createGpuProcess, params, gpuPreferences)); + } + ~GpuThreadControllerQt() override + { + base::PostTaskWithTraits( + FROM_HERE, { content::BrowserThread::UI }, + base::BindOnce(&GpuThreadControllerQt::destroyGpuProcess)); + } + + static void createGpuProcess( + const content::InProcessChildThreadParams ¶ms, + const gpu::GpuPreferences &gpuPreferences) + { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + if (s_gpuProcessDestroyed) + return; + + s_gpuProcess = std::make_unique<content::GpuProcess>(base::ThreadPriority::DISPLAY); + auto gpuInit = std::make_unique<gpu::GpuInit>(); + gpuInit->InitializeInProcess(base::CommandLine::ForCurrentProcess(), gpuPreferences); + auto childThread = new content::GpuChildThread(params, std::move(gpuInit)); + childThread->Init(base::Time::Now()); + s_gpuProcess->set_main_thread(childThread); + } + + static void destroyGpuProcess() + { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + if (s_gpuProcessDestroyed) + return; + + // viz::GpuServiceImpl::~GpuServiceImpl waits for io task. + base::ScopedAllowBaseSyncPrimitivesForTesting allow; + s_gpuProcess.reset(); + s_gpuProcessDestroyed = true; + } + + static std::unique_ptr<content::GpuProcess> s_gpuProcess; + static bool s_gpuProcessDestroyed; +}; + +std::unique_ptr<content::GpuProcess> GpuThreadControllerQt::s_gpuProcess; +bool GpuThreadControllerQt::s_gpuProcessDestroyed = false; + +static std::unique_ptr<content::GpuThreadController> createGpuThreadController( + const content::InProcessChildThreadParams ¶ms, + const gpu::GpuPreferences &gpuPreferences) +{ + return std::make_unique<GpuThreadControllerQt>(params, gpuPreferences); +} + +// static +void WebEngineContext::destroyGpuProcess() +{ + GpuThreadControllerQt::destroyGpuProcess(); +} + +// static +void WebEngineContext::registerMainThreadFactories(bool threaded) +{ + content::UtilityProcessHost::RegisterUtilityMainThreadFactory(content::CreateInProcessUtilityThread); + content::RenderProcessHostImpl::RegisterRendererMainThreadFactory(content::CreateInProcessRendererThread); + if (threaded) + content::RegisterGpuMainThreadFactory(content::CreateInProcessGpuThread); + else + content::RegisterGpuMainThreadFactory(createGpuThreadController); +} + +} // namespace QtWebEngineCore diff --git a/src/core/web_engine_error.h b/src/core/web_engine_error.h index 20af6d31f..cda9e4625 100644 --- a/src/core/web_engine_error.h +++ b/src/core/web_engine_error.h @@ -53,7 +53,7 @@ #include "qtwebenginecoreglobal_p.h" -class QWEBENGINECORE_PRIVATE_EXPORT WebEngineError +class Q_WEBENGINECORE_PRIVATE_EXPORT WebEngineError { public: diff --git a/src/core/web_engine_library_info.cpp b/src/core/web_engine_library_info.cpp index 3899ced25..1c8316430 100644 --- a/src/core/web_engine_library_info.cpp +++ b/src/core/web_engine_library_info.cpp @@ -54,6 +54,7 @@ #include <QDir> #include <QFileInfo> #include <QLibraryInfo> +#include <QLocale> #include <QStandardPaths> #include <QString> @@ -256,34 +257,6 @@ QString dictionariesPath() } #endif // QT_CONFIG(webengine_spellchecker) -QString icuDataPath() -{ - static bool initialized = false; - static QString potentialResourcesPath = -#if defined(OS_MACOSX) && defined(QT_MAC_FRAMEWORK_BUILD) - getResourcesPath(frameworkBundle()); -#else - QLibraryInfo::location(QLibraryInfo::DataPath) % QLatin1String("/resources"); -#endif - if (!initialized) { - initialized = true; - if (!QFileInfo::exists(potentialResourcesPath % QLatin1String("/icudtl.dat"))) { - qWarning("Qt WebEngine ICU data not found at %s. Trying parent directory...", qPrintable(potentialResourcesPath)); - potentialResourcesPath = QLibraryInfo::location(QLibraryInfo::DataPath); - } - if (!QFileInfo::exists(potentialResourcesPath % QLatin1String("/icudtl.dat"))) { - qWarning("Qt WebEngine ICU data not found at %s. Trying application directory...", qPrintable(potentialResourcesPath)); - potentialResourcesPath = QCoreApplication::applicationDirPath(); - } - if (!QFileInfo::exists(potentialResourcesPath % QLatin1String("/icudtl.dat"))) { - qWarning("Qt WebEngine ICU data not found at %s. Trying fallback directory... The application MAY NOT work.", qPrintable(potentialResourcesPath)); - potentialResourcesPath = fallbackDir(); - } - } - - return potentialResourcesPath; -} - QString resourcesDataPath() { static bool initialized = false; @@ -340,7 +313,7 @@ base::FilePath WebEngineLibraryInfo::getPath(int key) directory = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); break; case base::DIR_QT_LIBRARY_DATA: - return toFilePath(icuDataPath()); + return toFilePath(resourcesDataPath()); case ui::DIR_LOCALES: return toFilePath(localesPath()); #if QT_CONFIG(webengine_spellchecker) diff --git a/src/core/web_engine_settings.cpp b/src/core/web_engine_settings.cpp index 664951e66..b6250a65f 100644 --- a/src/core/web_engine_settings.cpp +++ b/src/core/web_engine_settings.cpp @@ -283,6 +283,11 @@ void WebEngineSettings::initDefaults() s_defaultAttributes.insert(WebRTCPublicInterfacesOnly, false); s_defaultAttributes.insert(JavascriptCanPaste, false); s_defaultAttributes.insert(DnsPrefetchEnabled, false); +#if QT_CONFIG(webengine_extensions) + s_defaultAttributes.insert(PdfViewerEnabled, true); +#else + s_defaultAttributes.insert(PdfViewerEnabled, false); +#endif } if (s_defaultFontFamilies.isEmpty()) { @@ -340,6 +345,10 @@ void WebEngineSettings::applySettingsToWebPreferences(content::WebPreferences *p { // Override for now prefs->touch_event_feature_detection_enabled = isTouchEventsAPIEnabled(); +#if !QT_CONFIG(webengine_embedded_build) + prefs->available_hover_types = ui::HOVER_TYPE_HOVER; + prefs->primary_hover_type = ui::HOVER_TYPE_HOVER; +#endif if (prefs->viewport_enabled) { // We need to enable the viewport options together as it doesn't really work // to enable them separately. With viewport-enabled we match Android defaults. diff --git a/src/core/web_engine_settings.h b/src/core/web_engine_settings.h index 8930d7c27..b2a45098a 100644 --- a/src/core/web_engine_settings.h +++ b/src/core/web_engine_settings.h @@ -68,7 +68,7 @@ namespace QtWebEngineCore { class WebContentsAdapter; -class QWEBENGINECORE_PRIVATE_EXPORT WebEngineSettings { +class Q_WEBENGINECORE_PRIVATE_EXPORT WebEngineSettings { public: // Attributes. Names match the ones from the public widgets API. enum Attribute { @@ -103,6 +103,7 @@ public: WebRTCPublicInterfacesOnly, JavascriptCanPaste, DnsPrefetchEnabled, + PdfViewerEnabled, }; // Must match the values from the public API in qwebenginesettings.h. diff --git a/src/core/web_event_factory.cpp b/src/core/web_event_factory.cpp index fc6287dd9..a0fac73ec 100644 --- a/src/core/web_event_factory.cpp +++ b/src/core/web_event_factory.cpp @@ -101,7 +101,7 @@ static KeyboardDriver keyboardDriverImpl() if (platformName == QLatin1Literal("xcb") || platformName == QLatin1Literal("wayland")) return KeyboardDriver::Xkb; -#if QT_CONFIG(libinput) && QT_CONFIG(xkbcommon) +#if QT_CONFIG(libinput) // Based on QEglFSIntegration::createInputHandlers and QLibInputKeyboard::processKey. if (platformName == QLatin1Literal("eglfs") && !qEnvironmentVariableIntValue("QT_QPA_EGLFS_NO_LIBINPUT")) return KeyboardDriver::Xkb; @@ -926,7 +926,7 @@ static ui::DomKey domKeyForQtKey(int qtKey) return ui::DomKey::ZENKAKU; case Qt::Key_Zenkaku_Hankaku: return ui::DomKey::ZENKAKU_HANKAKU; - +#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) // Dead keys (ui/events/keycodes/keyboard_code_conversion_xkb.cc) case Qt::Key_Dead_Grave: return ui::DomKey::DeadKeyFromCombiningCharacter(0x0300); @@ -994,7 +994,7 @@ static ui::DomKey domKeyForQtKey(int qtKey) return ui::DomKey::DeadKeyFromCombiningCharacter(0x00A4); case Qt::Key_Dead_Greek: return ui::DomKey::DeadKeyFromCombiningCharacter(0x037E); - +#endif // General-Purpose Function Keys case Qt::Key_F1: return ui::DomKey::F1; @@ -1354,10 +1354,10 @@ static WebPointerProperties::PointerType pointerTypeForTabletEvent(const QTablet } #endif -WebMouseEvent WebEventFactory::toWebMouseEvent(QMouseEvent *ev, double dpiScale) +WebMouseEvent WebEventFactory::toWebMouseEvent(QMouseEvent *ev) { WebMouseEvent webKitEvent(webEventTypeForEvent(ev), - WebFloatPoint(ev->x() / dpiScale, ev->y() / dpiScale), + WebFloatPoint(ev->x(), ev->y()), WebFloatPoint(ev->globalX(), ev->globalY()), mouseButtonForEvent<QMouseEvent>(ev), 0, @@ -1369,14 +1369,14 @@ WebMouseEvent WebEventFactory::toWebMouseEvent(QMouseEvent *ev, double dpiScale) return webKitEvent; } -WebMouseEvent WebEventFactory::toWebMouseEvent(QHoverEvent *ev, double dpiScale) +WebMouseEvent WebEventFactory::toWebMouseEvent(QHoverEvent *ev) { WebMouseEvent webKitEvent; webKitEvent.SetTimeStamp(base::TimeTicks::Now()); webKitEvent.SetModifiers(modifiersForEvent(ev)); webKitEvent.SetType(webEventTypeForEvent(ev)); - webKitEvent.SetPositionInWidget(ev->pos().x() / dpiScale, ev->pos().y() / dpiScale); + webKitEvent.SetPositionInWidget(ev->pos().x(), ev->pos().y()); webKitEvent.movement_x = ev->pos().x() - ev->oldPos().x(); webKitEvent.movement_y = ev->pos().y() - ev->oldPos().y(); webKitEvent.pointer_type = WebPointerProperties::PointerType::kMouse; @@ -1385,10 +1385,10 @@ WebMouseEvent WebEventFactory::toWebMouseEvent(QHoverEvent *ev, double dpiScale) } #if QT_CONFIG(tabletevent) -WebMouseEvent WebEventFactory::toWebMouseEvent(QTabletEvent *ev, double dpiScale) +WebMouseEvent WebEventFactory::toWebMouseEvent(QTabletEvent *ev) { WebMouseEvent webKitEvent(webEventTypeForEvent(ev), - WebFloatPoint(ev->x() / dpiScale, ev->y() / dpiScale), + WebFloatPoint(ev->x(), ev->y()), WebFloatPoint(ev->globalX(), ev->globalY()), mouseButtonForEvent<QTabletEvent>(ev), 0, @@ -1416,17 +1416,17 @@ WebMouseEvent WebEventFactory::toWebMouseEvent(QEvent *ev) } #ifndef QT_NO_GESTURES -WebGestureEvent WebEventFactory::toWebGestureEvent(QNativeGestureEvent *ev, double dpiScale) +WebGestureEvent WebEventFactory::toWebGestureEvent(QNativeGestureEvent *ev) { WebGestureEvent webKitEvent; webKitEvent.SetTimeStamp(base::TimeTicks::Now()); webKitEvent.SetModifiers(modifiersForEvent(ev)); - webKitEvent.SetPositionInWidget(WebFloatPoint(ev->localPos().x() / dpiScale, - ev->localPos().y() / dpiScale)); + webKitEvent.SetPositionInWidget(WebFloatPoint(ev->localPos().x(), + ev->localPos().y())); - webKitEvent.SetPositionInScreen(WebFloatPoint(ev->screenPos().x() / dpiScale, - ev->screenPos().y() / dpiScale)); + webKitEvent.SetPositionInScreen(WebFloatPoint(ev->screenPos().x(), + ev->screenPos().y())); webKitEvent.SetSourceDevice(blink::kWebGestureDeviceTouchpad); @@ -1484,13 +1484,13 @@ blink::WebMouseWheelEvent::Phase toBlinkPhase(QWheelEvent *ev) return blink::WebMouseWheelEvent::kPhaseNone; } -blink::WebMouseWheelEvent WebEventFactory::toWebWheelEvent(QWheelEvent *ev, double dpiScale) +blink::WebMouseWheelEvent WebEventFactory::toWebWheelEvent(QWheelEvent *ev) { WebMouseWheelEvent webEvent; webEvent.SetType(webEventTypeForEvent(ev)); webEvent.SetModifiers(modifiersForEvent(ev)); webEvent.SetTimeStamp(base::TimeTicks::Now()); - webEvent.SetPositionInWidget(ev->x() / dpiScale, ev->y() / dpiScale); + webEvent.SetPositionInWidget(ev->x(), ev->y()); webEvent.SetPositionInScreen(ev->globalX(), ev->globalY()); webEvent.wheel_ticks_x = static_cast<float>(ev->angleDelta().x()) / QWheelEvent::DefaultDeltasPerStep; @@ -1506,7 +1506,7 @@ blink::WebMouseWheelEvent WebEventFactory::toWebWheelEvent(QWheelEvent *ev, doub return webEvent; } -bool WebEventFactory::coalesceWebWheelEvent(blink::WebMouseWheelEvent &webEvent, QWheelEvent *ev, double dpiScale) +bool WebEventFactory::coalesceWebWheelEvent(blink::WebMouseWheelEvent &webEvent, QWheelEvent *ev) { if (webEventTypeForEvent(ev) != webEvent.GetType()) return false; @@ -1520,7 +1520,7 @@ bool WebEventFactory::coalesceWebWheelEvent(blink::WebMouseWheelEvent &webEvent, #endif webEvent.SetTimeStamp(base::TimeTicks::Now()); - webEvent.SetPositionInWidget(ev->x() / dpiScale, ev->y() / dpiScale); + webEvent.SetPositionInWidget(ev->x(), ev->y()); webEvent.SetPositionInScreen(ev->globalX(), ev->globalY()); webEvent.wheel_ticks_x += static_cast<float>(ev->angleDelta().x()) / QWheelEvent::DefaultDeltasPerStep; diff --git a/src/core/web_event_factory.h b/src/core/web_event_factory.h index 4b22de7d7..526202cfb 100644 --- a/src/core/web_event_factory.h +++ b/src/core/web_event_factory.h @@ -66,17 +66,17 @@ QT_END_NAMESPACE class WebEventFactory { public: - static blink::WebMouseEvent toWebMouseEvent(QMouseEvent*, double dpiScale); - static blink::WebMouseEvent toWebMouseEvent(QHoverEvent*, double dpiScale); + static blink::WebMouseEvent toWebMouseEvent(QMouseEvent *); + static blink::WebMouseEvent toWebMouseEvent(QHoverEvent *); #ifndef QT_NO_TABLETEVENT - static blink::WebMouseEvent toWebMouseEvent(QTabletEvent*, double dpiScale); + static blink::WebMouseEvent toWebMouseEvent(QTabletEvent *); #endif static blink::WebMouseEvent toWebMouseEvent(QEvent *); #ifndef QT_NO_GESTURES - static blink::WebGestureEvent toWebGestureEvent(QNativeGestureEvent *, double dpiScale); + static blink::WebGestureEvent toWebGestureEvent(QNativeGestureEvent *); #endif - static blink::WebMouseWheelEvent toWebWheelEvent(QWheelEvent*, double dpiScale); - static bool coalesceWebWheelEvent(blink::WebMouseWheelEvent &, QWheelEvent*, double dpiScale); + static blink::WebMouseWheelEvent toWebWheelEvent(QWheelEvent *); + static bool coalesceWebWheelEvent(blink::WebMouseWheelEvent &, QWheelEvent *); static content::NativeWebKeyboardEvent toWebKeyboardEvent(QKeyEvent*); static bool getEditCommand(QKeyEvent *event, std::string *editCommand); }; diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro index 32fce325b..6698a9736 100644 --- a/src/plugins/plugins.pro +++ b/src/plugins/plugins.pro @@ -1,2 +1,2 @@ TEMPLATE = subdirs -qtHaveModule(designer):qtHaveModule(webenginewidgets): SUBDIRS += qwebengineview +qtHaveModule(designer): SUBDIRS += qwebengineview diff --git a/src/src.pro b/src/src.pro index 218cdb66d..30562686a 100644 --- a/src/src.pro +++ b/src/src.pro @@ -14,11 +14,7 @@ core.depends = buildtools SUBDIRS += buildtools \ core \ - process \ - webengine \ - webengine_plugin \ - plugins - + process qtConfig(webengine-spellchecker):!qtConfig(webengine-native-spellchecker):!cross_compile { SUBDIRS += qwebengine_convert_dict @@ -26,19 +22,11 @@ qtConfig(webengine-spellchecker):!qtConfig(webengine-native-spellchecker):!cross qwebengine_convert_dict.depends = core } -qtConfig(webengine-testsupport) { - webengine_testsupport_plugin.subdir = webengine/plugin/testsupport - webengine_testsupport_plugin.target = sub-webengine-testsupport-plugin - webengine_testsupport_plugin.depends = webengine - SUBDIRS += webengine_testsupport_plugin -} - -qtConfig(webengine-ui-delegates) { - SUBDIRS += webengine/ui \ - webengine/ui2 +qtConfig(webengine-qml) { + SUBDIRS += webengine } -qtHaveModule(widgets) { - SUBDIRS += webenginewidgets +qtConfig(webengine-widgets) { + SUBDIRS += plugins webenginewidgets plugins.depends = webenginewidgets } diff --git a/src/tools/qwebengine_convert_dict/main.cpp b/src/tools/qwebengine_convert_dict/main.cpp index 9d3888ad6..1694dbcef 100644 --- a/src/tools/qwebengine_convert_dict/main.cpp +++ b/src/tools/qwebengine_convert_dict/main.cpp @@ -111,7 +111,9 @@ inline bool VerifyWords(const convert_dict::DicReader::WordList& org_words, base::span<const int> expectedAffixes(org_words[i].second); base::span<const int> actualAffixes(affix_ids, affix_matches); - if (expectedAffixes != actualAffixes) { + if (!std::equal(expectedAffixes.begin(), expectedAffixes.end(), + actualAffixes.begin(), actualAffixes.end(), + [](int a, int b) { return a == b; })) { out << "Affixes do not match!\n" << " Index: " << i << "\n" << " Word: " << QString::fromUtf8(buf) << "\n" diff --git a/src/tools/qwebengine_convert_dict/qwebengine_convert_dict.pro b/src/tools/qwebengine_convert_dict/qwebengine_convert_dict.pro index ced90655e..27edd66d8 100644 --- a/src/tools/qwebengine_convert_dict/qwebengine_convert_dict.pro +++ b/src/tools/qwebengine_convert_dict/qwebengine_convert_dict.pro @@ -39,6 +39,8 @@ SOURCES += \ QMAKE_TARGET_DESCRIPTION = "Qt WebEngine Dictionary Converter" +CONFIG += c++14 + # Support converting dictionaries in a prefix build, by supplying # the path to the ICU data file located in the Qt build path, rather # than the install path (which is not present at build time). diff --git a/src/webengine/api/qquickwebengineclientcertificateselection.cpp b/src/webengine/api/qquickwebengineclientcertificateselection.cpp new file mode 100644 index 000000000..c48a59887 --- /dev/null +++ b/src/webengine/api/qquickwebengineclientcertificateselection.cpp @@ -0,0 +1,226 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickwebengineclientcertificateselection_p.h" + +#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) + +#include "client_cert_select_controller.h" + +QT_BEGIN_NAMESPACE + +/*! + \qmltype WebEngineClientCertificateOption + \instantiates QQuickWebEngineClientCertificateOption + \inqmlmodule QtWebEngine + \since QtWebEngine 1.9 + \brief Represents a client certificate option. + + \sa {WebEngineClientCertificateSelection::certificates} {WebEngineClientCertificateSelection.certificates} +*/ + +QQuickWebEngineClientCertificateOption::QQuickWebEngineClientCertificateOption(QQuickWebEngineClientCertificateSelection *selection, int index) + : QObject(selection), m_selection(selection), m_index(index) +{} + +/*! + \qmlproperty string WebEngineClientCertificateOption::issuer + \brief The issuer of the certificate. +*/ + +QString QQuickWebEngineClientCertificateOption::issuer() const +{ + return m_selection->d_ptr->certificates().at(m_index).issuerDisplayName(); +} + +/*! + \qmlproperty string WebEngineClientCertificateOption::subject + \brief The subject of the certificate. +*/ +QString QQuickWebEngineClientCertificateOption::subject() const +{ + return m_selection->d_ptr->certificates().at(m_index).subjectDisplayName(); +} + +/*! + \qmlproperty datetime WebEngineClientCertificateOption::effectiveDate + \brief The date and time when the certificate becomes valid. +*/ +QDateTime QQuickWebEngineClientCertificateOption::effectiveDate() const +{ + return m_selection->d_ptr->certificates().at(m_index).effectiveDate(); +} + +/*! + \qmlproperty datetime WebEngineClientCertificateOption::expiryDate + \brief The date and time when the certificate becomes invalid. +*/ +QDateTime QQuickWebEngineClientCertificateOption::expiryDate() const +{ + return m_selection->d_ptr->certificates().at(m_index).expiryDate(); +} + +/*! + \qmlproperty bool WebEngineClientCertificateOption::isSelfSigned + \brief Whether the certificate is only self-signed. +*/ +bool QQuickWebEngineClientCertificateOption::isSelfSigned() const +{ + return m_selection->d_ptr->certificates().at(m_index).isSelfSigned(); +} + +/*! + \qmlmethod void WebEngineClientCertificateOption::select() + + Selects this client certificate option. +*/ +void QQuickWebEngineClientCertificateOption::select() +{ + m_selection->select(m_index); +} + +/*! + \qmltype WebEngineClientCertificateSelection + \instantiates QQuickWebEngineClientCertificateSelection + \inqmlmodule QtWebEngine + \since QtWebEngine 1.9 + \brief Provides a selection of client certificates. + + When a web site requests an SSL client certificate, and one or more certificates + are found in the system's client certificate store, this type provides access to + the certificates to choose from, as well as a method for selecting one. + + The selection is asynchronous. If no certificate is selected and no copy of the + object is kept alive, loading will continue without a certificate. + + \sa {WebEngineView::selectClientCertificate}{WebEngineView.selectClientCertificate} +*/ + +QQuickWebEngineClientCertificateSelection::QQuickWebEngineClientCertificateSelection(QSharedPointer<ClientCertSelectController> selectController) + : QObject(), d_ptr(selectController) +{} + +int QQuickWebEngineClientCertificateSelection::certificates_count( + QQmlListProperty<QQuickWebEngineClientCertificateOption> *p) +{ + Q_ASSERT(p && p->object); + QQuickWebEngineClientCertificateSelection *d = static_cast<QQuickWebEngineClientCertificateSelection *>(p->object); + return d->m_certificates.size(); +} + +QQuickWebEngineClientCertificateOption *QQuickWebEngineClientCertificateSelection::certificates_at( + QQmlListProperty<QQuickWebEngineClientCertificateOption> *p, int idx) +{ + Q_ASSERT(p && p->object); + QQuickWebEngineClientCertificateSelection *d = static_cast<QQuickWebEngineClientCertificateSelection *>(p->object); + if (idx < 0 || idx >= d->m_certificates.size()) + return nullptr; + return d->m_certificates[idx]; +} + +/*! + \qmlproperty list<WebEngineClientCertificateOption> WebEngineClientCertificateSelection::certificates + \brief The client certificates available to choose from. +*/ + +QQmlListProperty<QQuickWebEngineClientCertificateOption> QQuickWebEngineClientCertificateSelection::certificates() +{ + if (m_certificates.empty()) { + QVector<QSslCertificate> certificates = d_ptr->certificates(); + for (int i = 0; i < certificates.count(); ++i) + m_certificates.push_back(new QQuickWebEngineClientCertificateOption(this, i)); + } + + return QQmlListProperty<QQuickWebEngineClientCertificateOption>( + this, nullptr, + certificates_count, + certificates_at); +} + +/*! + \qmlmethod void WebEngineClientCertificateSelection::select(WebEngineClientCertificateOption certificate) + + Selects the client certificate \a certificate. The certificate must be one + of the offered certificates. + + \sa selectNone() +*/ +void QQuickWebEngineClientCertificateSelection::select(const QQuickWebEngineClientCertificateOption *certificate) +{ + select(certificate->m_index); +} + +/*! + \qmlmethod void WebEngineClientCertificateSelection::select(int index) + + Selects the client certificate at the index \a index in the list of offered certificates. + + \sa selectNone() +*/ +void QQuickWebEngineClientCertificateSelection::select(int index) +{ + d_ptr->select(index); +} + +/*! + \qmlmethod void WebEngineClientCertificateSelection::selectNone() + + Continues without using any of the offered certificates. This is the same + action as taken when destroying the last copy of this object if no + selection has been made. + + \sa select() +*/ +void QQuickWebEngineClientCertificateSelection::selectNone() +{ + d_ptr->selectNone(); +} + +/*! + \qmlproperty url WebEngineClientCertificateSelection::host + \brief The host and port of the server requesting the client certificate. +*/ +QUrl QQuickWebEngineClientCertificateSelection::host() const +{ + return d_ptr->hostAndPort(); +} + +QT_END_NAMESPACE + +#endif // QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) diff --git a/src/webengine/api/qquickwebengineclientcertificateselection_p.h b/src/webengine/api/qquickwebengineclientcertificateselection_p.h new file mode 100644 index 000000000..adf8b5f7c --- /dev/null +++ b/src/webengine/api/qquickwebengineclientcertificateselection_p.h @@ -0,0 +1,131 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKWEBENGINECERTSELECTION_P_H +#define QQUICKWEBENGINECERTSELECTION_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 <QtWebEngine/private/qtwebengineglobal_p.h> + +#include <QtCore/QDateTime> +#include <QtCore/QObject> +#include <QtCore/QSharedPointer> +#include <QtCore/QUrl> +#include <QtCore/QVector> +#include <QtQml/QQmlListProperty> + +#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) + +QT_BEGIN_NAMESPACE + +class ClientCertSelectController; +class QQuickWebEngineClientCertificateSelection; + +class Q_WEBENGINE_PRIVATE_EXPORT QQuickWebEngineClientCertificateOption : public QObject { + Q_OBJECT + Q_PROPERTY(QString issuer READ issuer CONSTANT FINAL) + Q_PROPERTY(QString subject READ subject CONSTANT FINAL) + Q_PROPERTY(QDateTime effectiveDate READ effectiveDate CONSTANT FINAL) + Q_PROPERTY(QDateTime expiryDate READ expiryDate CONSTANT FINAL) + Q_PROPERTY(bool isSelfSigned READ isSelfSigned CONSTANT FINAL) + +public: + QString issuer() const; + QString subject() const; + QDateTime effectiveDate() const; + QDateTime expiryDate() const; + bool isSelfSigned() const; + + Q_INVOKABLE void select(); + +private: + friend class QQuickWebEngineClientCertificateSelection; + QQuickWebEngineClientCertificateOption(QQuickWebEngineClientCertificateSelection *selection, int index); + + QQuickWebEngineClientCertificateSelection *m_selection; + int m_index; +}; + +class Q_WEBENGINE_PRIVATE_EXPORT QQuickWebEngineClientCertificateSelection : public QObject { + Q_OBJECT + Q_PROPERTY(QUrl host READ host CONSTANT FINAL) + Q_PROPERTY(QQmlListProperty<QQuickWebEngineClientCertificateOption> certificates READ certificates CONSTANT FINAL) + +public: + QQuickWebEngineClientCertificateSelection() = default; + + QUrl host() const; + + Q_INVOKABLE void select(int idx); + Q_INVOKABLE void select(const QQuickWebEngineClientCertificateOption *certificate); + Q_INVOKABLE void selectNone(); + QQmlListProperty<QQuickWebEngineClientCertificateOption> certificates(); + +private: + friend class QQuickWebEngineViewPrivate; + friend class QQuickWebEngineClientCertificateOption; + + static int certificates_count(QQmlListProperty<QQuickWebEngineClientCertificateOption> *p); + static QQuickWebEngineClientCertificateOption *certificates_at(QQmlListProperty<QQuickWebEngineClientCertificateOption> *p, int idx); + + explicit QQuickWebEngineClientCertificateSelection(QSharedPointer<ClientCertSelectController>); + + mutable QVector<QQuickWebEngineClientCertificateOption *> m_certificates; + QSharedPointer<ClientCertSelectController> d_ptr; +}; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QQuickWebEngineClientCertificateOption *) +Q_DECLARE_METATYPE(QQmlListProperty<QQuickWebEngineClientCertificateOption>) +Q_DECLARE_METATYPE(QQuickWebEngineClientCertificateSelection *) + +#endif + +#endif // QQUICKWEBENGINECERTSELECTION_P_H diff --git a/src/webengine/api/qquickwebengineprofile.cpp b/src/webengine/api/qquickwebengineprofile.cpp index f77f376aa..7630587fe 100644 --- a/src/webengine/api/qquickwebengineprofile.cpp +++ b/src/webengine/api/qquickwebengineprofile.cpp @@ -46,6 +46,7 @@ #include "qquickwebenginesettings_p.h" #include "qquickwebengineview_p_p.h" #include "qwebenginecookiestore.h" +#include "qwebenginenotification.h" #include <QQmlEngine> @@ -150,6 +151,16 @@ ASSERT_ENUMS_MATCH(QQuickWebEngineDownloadItem::MimeHtmlSaveFormat, QtWebEngineC The \a download argument holds the state of the finished download instance. */ +/*! + \fn QQuickWebEngineProfile::presentNotification(QWebEngineNotification *notification) + + This signal is emitted whenever there is a newly created user notification. + The \a notification argument holds the \l {QWebEngineNotification} instance + to query data and interact with. + + \sa WebEngineProfile::presentNotification +*/ + QQuickWebEngineProfilePrivate::QQuickWebEngineProfilePrivate(ProfileAdapter *profileAdapter) : m_settings(new QQuickWebEngineSettings()) , m_profileAdapter(profileAdapter) @@ -285,6 +296,20 @@ void QQuickWebEngineProfilePrivate::downloadUpdated(const DownloadItemInfo &info } } +void QQuickWebEngineProfilePrivate::useForGlobalCertificateVerificationChanged() +{ + Q_Q(QQuickWebEngineProfile); + Q_EMIT q->useForGlobalCertificateVerificationChanged(); +} + +void QQuickWebEngineProfilePrivate::showNotification(QSharedPointer<QtWebEngineCore::UserNotificationController> &controller) +{ + Q_Q(QQuickWebEngineProfile); + auto notification = new QWebEngineNotification(controller); + QQmlEngine::setObjectOwnership(notification, QQmlEngine::JavaScriptOwnership); + Q_EMIT q->presentNotification(notification); +} + void QQuickWebEngineProfilePrivate::userScripts_append(QQmlListProperty<QQuickWebEngineScript> *p, QQuickWebEngineScript *script) { Q_ASSERT(p && p->data); @@ -365,6 +390,15 @@ void QQuickWebEngineProfilePrivate::userScripts_clear(QQmlListProperty<QQuickWeb */ /*! + \qmlsignal WebEngineProfile::presentNotification(WebEngineNotification notification) + \since QtWebEngine 1.9 + + This signal is emitted whenever there is a newly created user notification. + The \a notification argument holds the \l {WebEngineNotification} instance + to query data and interact with. +*/ + +/*! Constructs a new profile with the parent \a parent. */ QQuickWebEngineProfile::QQuickWebEngineProfile(QObject *parent) @@ -796,6 +830,102 @@ bool QQuickWebEngineProfile::isSpellCheckEnabled() const } /*! + \property QQuickWebEngineProfile::useForGlobalCertificateVerification + \since 5.13 + + This property holds whether this profile is used for downloading and + caching during global certificate verification when using the online + certificate status protocol (OCSP), certificate revokation lists (CRLs), + and authority information access (AIA), for example. + + As long as one profile has this option enabled, all other profiles will be + able to use it for certificate verification. Only one profile at a time can + have this option enabled. It is recommended that the profile has a disk HTTP + cache to avoid needlessly re-downloading. + + By default, no profile has this property enabled. + + Currently, only affects Linux/NSS installations, where having a profile with + this role enables OCSP. +*/ + +/*! + \qmlproperty bool WebEngineProfile::useForGlobalCertificateVerification + \since QtWebEngine 1.9 + + This property holds whether this profile is used for downloading and + caching during global certificate verification when using the online + certificate status protocol (OCSP), certificate revokation lists (CRLs), + and authority information access (AIA), for example. + + As long as one profile has this option enabled, all other profiles will be + able to use it for certificate verification. Only one profile at a time can + have this option enabled. It is recommended that the profile has a disk HTTP + cache to avoid needlessly re-downloading. + + By default, no profile has this property enabled. + + Currently, only affects Linux/NSS installations, where having a profile with + this role enables OCSP. +*/ + +void QQuickWebEngineProfile::setUseForGlobalCertificateVerification(bool enable) +{ + Q_D(QQuickWebEngineProfile); + if (enable != d->profileAdapter()->isUsedForGlobalCertificateVerification()) { + d->profileAdapter()->setUseForGlobalCertificateVerification(enable); + emit useForGlobalCertificateVerificationChanged(); + } +} + +bool QQuickWebEngineProfile::isUsedForGlobalCertificateVerification() const +{ + const Q_D(QQuickWebEngineProfile); + return d->profileAdapter()->isUsedForGlobalCertificateVerification(); +} + +/*! + \qmlproperty string WebEngineProfile::downloadPath + \since QtWebEngine 1.9 + + The path to the location where the downloaded files are stored. + + Overrides the default path used for download location. + + If set to an empty string, the default path is restored. + + \note By default, the download path is QStandardPaths::DownloadLocation. +*/ + +/*! + \property QQuickWebEngineProfile::downloadPath + \since QtWebEngine 1.9 + + The path to the location where the downloaded files are stored. + + Overrides the default path used for download location, setting it to \a path. + + If set to an empty string, the default path is restored. + + \note By default, the download path is QStandardPaths::DownloadLocation. +*/ + +void QQuickWebEngineProfile::setDownloadPath(const QString &path) +{ + Q_D(QQuickWebEngineProfile); + if (downloadPath() == path) + return; + d->profileAdapter()->setDownloadPath(path); + emit downloadPathChanged(); +} + +QString QQuickWebEngineProfile::downloadPath() const +{ + const Q_D(QQuickWebEngineProfile); + return d->profileAdapter()->downloadPath(); +} + +/*! Returns the cookie store for this profile. */ @@ -827,27 +957,52 @@ void QQuickWebEngineProfile::clearHttpCache() d->profileAdapter()->clearHttpCache(); } - +#if QT_DEPRECATED_SINCE(5, 13) /*! Registers a request interceptor singleton \a interceptor to intercept URL requests. The profile does not take ownership of the pointer. + \obsolete + + Interceptors installed with this method will call + QWebEngineUrlRequestInterceptor::interceptRequest on the I/O thread. Therefore + the user has to provide thread-safe interaction with the other user classes. + Use setUrlRequestInterceptor instead. + \sa QWebEngineUrlRequestInterceptor + */ void QQuickWebEngineProfile::setRequestInterceptor(QWebEngineUrlRequestInterceptor *interceptor) { Q_D(QQuickWebEngineProfile); + interceptor->setProperty("deprecated", true); + d->profileAdapter()->setRequestInterceptor(interceptor); + qWarning("Use of deprecated not tread-safe setter, use setUrlRequestInterceptor instead."); +} +#endif + +/*! + Registers a request interceptor singleton \a interceptor to intercept URL requests. + + The profile does not take ownership of the pointer. + + \sa QWebEngineUrlRequestInfo QWebEngineUrlRequestInterceptor +*/ +void QQuickWebEngineProfile::setUrlRequestInterceptor(QWebEngineUrlRequestInterceptor *interceptor) +{ + Q_D(QQuickWebEngineProfile); d->profileAdapter()->setRequestInterceptor(interceptor); } + /*! Returns the custom URL scheme handler register for the URL scheme \a scheme. */ const QWebEngineUrlSchemeHandler *QQuickWebEngineProfile::urlSchemeHandler(const QByteArray &scheme) const { const Q_D(QQuickWebEngineProfile); - return d->profileAdapter()->customUrlSchemeHandlers().value(scheme.toLower()); + return d->profileAdapter()->urlSchemeHandler(scheme); } /*! @@ -859,10 +1014,7 @@ const QWebEngineUrlSchemeHandler *QQuickWebEngineProfile::urlSchemeHandler(const void QQuickWebEngineProfile::installUrlSchemeHandler(const QByteArray &scheme, QWebEngineUrlSchemeHandler *handler) { Q_D(QQuickWebEngineProfile); - Q_ASSERT(handler); - if (!d->profileAdapter()->addCustomUrlSchemeHandler(scheme, handler)) - return; - connect(handler, SIGNAL(_q_destroyedUrlSchemeHandler(QWebEngineUrlSchemeHandler*)), this, SLOT(destroyedUrlSchemeHandler(QWebEngineUrlSchemeHandler*))); + d->profileAdapter()->installUrlSchemeHandler(scheme, handler); } /*! @@ -873,10 +1025,7 @@ void QQuickWebEngineProfile::installUrlSchemeHandler(const QByteArray &scheme, Q void QQuickWebEngineProfile::removeUrlSchemeHandler(QWebEngineUrlSchemeHandler *handler) { Q_D(QQuickWebEngineProfile); - Q_ASSERT(handler); - if (!d->profileAdapter()->removeCustomUrlSchemeHandler(handler)) - return; - disconnect(handler, SIGNAL(_q_destroyedUrlSchemeHandler(QWebEngineUrlSchemeHandler*)), this, SLOT(destroyedUrlSchemeHandler(QWebEngineUrlSchemeHandler*))); + d->profileAdapter()->removeUrlSchemeHandler(handler); } /*! @@ -887,10 +1036,7 @@ void QQuickWebEngineProfile::removeUrlSchemeHandler(QWebEngineUrlSchemeHandler * void QQuickWebEngineProfile::removeUrlScheme(const QByteArray &scheme) { Q_D(QQuickWebEngineProfile); - QWebEngineUrlSchemeHandler *handler = d->profileAdapter()->takeCustomUrlSchemeHandler(scheme); - if (!handler) - return; - disconnect(handler, SIGNAL(_q_destroyedUrlSchemeHandler(QWebEngineUrlSchemeHandler*)), this, SLOT(destroyedUrlSchemeHandler(QWebEngineUrlSchemeHandler*))); + d->profileAdapter()->removeUrlScheme(scheme); } /*! @@ -899,12 +1045,7 @@ void QQuickWebEngineProfile::removeUrlScheme(const QByteArray &scheme) void QQuickWebEngineProfile::removeAllUrlSchemeHandlers() { Q_D(QQuickWebEngineProfile); - d->profileAdapter()->clearCustomUrlSchemeHandlers(); -} - -void QQuickWebEngineProfile::destroyedUrlSchemeHandler(QWebEngineUrlSchemeHandler *obj) -{ - removeUrlSchemeHandler(obj); + d->profileAdapter()->removeAllUrlSchemeHandlers(); } QQuickWebEngineSettings *QQuickWebEngineProfile::settings() const @@ -942,4 +1083,19 @@ QQmlListProperty<QQuickWebEngineScript> QQuickWebEngineProfile::userScripts() d->userScripts_clear); } +/*! + \since 5.13 + + Returns the profile's client certificate store. +*/ +QWebEngineClientCertificateStore *QQuickWebEngineProfile::clientCertificateStore() +{ +#if QT_CONFIG(ssl) + Q_D(QQuickWebEngineProfile); + return d->profileAdapter()->clientCertificateStore(); +#else + return nullptr; +#endif +} + QT_END_NAMESPACE diff --git a/src/webengine/api/qquickwebengineprofile.h b/src/webengine/api/qquickwebengineprofile.h index 9fc4f9eca..e5f7ff713 100644 --- a/src/webengine/api/qquickwebengineprofile.h +++ b/src/webengine/api/qquickwebengineprofile.h @@ -54,7 +54,9 @@ class QQuickWebEngineDownloadItem; class QQuickWebEngineProfilePrivate; class QQuickWebEngineScript; class QQuickWebEngineSettings; +class QWebEngineClientCertificateStore; class QWebEngineCookieStore; +class QWebEngineNotification; class QWebEngineUrlRequestInterceptor; class QWebEngineUrlSchemeHandler; @@ -72,6 +74,12 @@ class Q_WEBENGINE_EXPORT QQuickWebEngineProfile : public QObject { Q_PROPERTY(QStringList spellCheckLanguages READ spellCheckLanguages WRITE setSpellCheckLanguages NOTIFY spellCheckLanguagesChanged FINAL REVISION 3) Q_PROPERTY(bool spellCheckEnabled READ isSpellCheckEnabled WRITE setSpellCheckEnabled NOTIFY spellCheckEnabledChanged FINAL REVISION 3) Q_PROPERTY(QQmlListProperty<QQuickWebEngineScript> userScripts READ userScripts FINAL REVISION 4) + Q_PROPERTY(bool useForGlobalCertificateVerification + READ isUsedForGlobalCertificateVerification + WRITE setUseForGlobalCertificateVerification + NOTIFY useForGlobalCertificateVerificationChanged + FINAL REVISION 5) + Q_PROPERTY(QString downloadPath READ downloadPath WRITE setDownloadPath NOTIFY downloadPathChanged FINAL REVISION 5) public: QQuickWebEngineProfile(QObject *parent = Q_NULLPTR); @@ -120,7 +128,10 @@ public: QWebEngineCookieStore *cookieStore() const; +#if QT_DEPRECATED_SINCE(5, 13) void setRequestInterceptor(QWebEngineUrlRequestInterceptor *interceptor); +#endif + void setUrlRequestInterceptor(QWebEngineUrlRequestInterceptor *interceptor); const QWebEngineUrlSchemeHandler *urlSchemeHandler(const QByteArray &) const; void installUrlSchemeHandler(const QByteArray &scheme, QWebEngineUrlSchemeHandler *); @@ -137,6 +148,14 @@ public: QQmlListProperty<QQuickWebEngineScript> userScripts(); + void setUseForGlobalCertificateVerification(bool b); + bool isUsedForGlobalCertificateVerification() const; + + QString downloadPath() const; + void setDownloadPath(const QString &path); + + QWebEngineClientCertificateStore *clientCertificateStore(); + static QQuickWebEngineProfile *defaultProfile(); Q_SIGNALS: @@ -151,12 +170,13 @@ Q_SIGNALS: Q_REVISION(1) void httpAcceptLanguageChanged(); Q_REVISION(3) void spellCheckLanguagesChanged(); Q_REVISION(3) void spellCheckEnabledChanged(); + Q_REVISION(5) void useForGlobalCertificateVerificationChanged(); + Q_REVISION(5) void downloadPathChanged(); void downloadRequested(QQuickWebEngineDownloadItem *download); void downloadFinished(QQuickWebEngineDownloadItem *download); -private Q_SLOTS: - void destroyedUrlSchemeHandler(QWebEngineUrlSchemeHandler *obj); + Q_REVISION(5) void presentNotification(QWebEngineNotification *notification); private: Q_DECLARE_PRIVATE(QQuickWebEngineProfile) diff --git a/src/webengine/api/qquickwebengineprofile_p.h b/src/webengine/api/qquickwebengineprofile_p.h index 41e513f4c..c6d412ab3 100644 --- a/src/webengine/api/qquickwebengineprofile_p.h +++ b/src/webengine/api/qquickwebengineprofile_p.h @@ -85,6 +85,10 @@ public: void downloadRequested(DownloadItemInfo &info) override; void downloadUpdated(const DownloadItemInfo &info) override; + void useForGlobalCertificateVerificationChanged() override; + + void showNotification(QSharedPointer<QtWebEngineCore::UserNotificationController> &controller) override; + // QQmlListPropertyHelpers static void userScripts_append(QQmlListProperty<QQuickWebEngineScript> *p, QQuickWebEngineScript *script); static int userScripts_count(QQmlListProperty<QQuickWebEngineScript> *p); diff --git a/src/webengine/api/qquickwebenginesettings.cpp b/src/webengine/api/qquickwebenginesettings.cpp index 6e96e76cf..9a102a504 100644 --- a/src/webengine/api/qquickwebenginesettings.cpp +++ b/src/webengine/api/qquickwebenginesettings.cpp @@ -250,7 +250,7 @@ bool QQuickWebEngineSettings::pluginsEnabled() const Tells the web engine whether fullscreen is supported in this application or not. - Enabled by default. + Disabled by default. */ bool QQuickWebEngineSettings::fullScreenSupportEnabled() const { @@ -457,6 +457,20 @@ bool QQuickWebEngineSettings::dnsPrefetchEnabled() const } /*! + \qmlproperty bool WebEngineSettings::pdfViewerEnabled + \since QtWebEngine 1.9 + + Specifies that PDF documents will be opened in the internal PDF viewer + instead of being downloaded. + + Enabled by default. +*/ +bool QQuickWebEngineSettings::pdfViewerEnabled() const +{ + return d_ptr->testAttribute(WebEngineSettings::PdfViewerEnabled); +} + +/*! \qmlproperty string WebEngineSettings::defaultTextEncoding \since QtWebEngine 1.2 @@ -714,6 +728,14 @@ void QQuickWebEngineSettings::setDnsPrefetchEnabled(bool on) Q_EMIT dnsPrefetchEnabledChanged(); } +void QQuickWebEngineSettings::setPdfViewerEnabled(bool on) +{ + bool wasOn = d_ptr->testAttribute(WebEngineSettings::PdfViewerEnabled); + d_ptr->setAttribute(WebEngineSettings::PdfViewerEnabled, on); + if (wasOn != on) + Q_EMIT pdfViewerEnabledChanged(); +} + void QQuickWebEngineSettings::setUnknownUrlSchemePolicy(QQuickWebEngineSettings::UnknownUrlSchemePolicy policy) { WebEngineSettings::UnknownUrlSchemePolicy oldPolicy = d_ptr->unknownUrlSchemePolicy(); diff --git a/src/webengine/api/qquickwebenginesettings_p.h b/src/webengine/api/qquickwebenginesettings_p.h index 6e1aaca39..ce43e0e9c 100644 --- a/src/webengine/api/qquickwebenginesettings_p.h +++ b/src/webengine/api/qquickwebenginesettings_p.h @@ -93,6 +93,7 @@ class Q_WEBENGINE_PRIVATE_EXPORT QQuickWebEngineSettings : public QObject { Q_PROPERTY(bool webRTCPublicInterfacesOnly READ webRTCPublicInterfacesOnly WRITE setWebRTCPublicInterfacesOnly NOTIFY webRTCPublicInterfacesOnlyChanged REVISION 6 FINAL) Q_PROPERTY(bool javascriptCanPaste READ javascriptCanPaste WRITE setJavascriptCanPaste NOTIFY javascriptCanPasteChanged REVISION 6 FINAL) Q_PROPERTY(bool dnsPrefetchEnabled READ dnsPrefetchEnabled WRITE setDnsPrefetchEnabled NOTIFY dnsPrefetchEnabledChanged REVISION 7 FINAL) + Q_PROPERTY(bool pdfViewerEnabled READ pdfViewerEnabled WRITE setPdfViewerEnabled NOTIFY pdfViewerEnabledChanged REVISION 8 FINAL) public: enum UnknownUrlSchemePolicy { @@ -135,6 +136,7 @@ public: bool webRTCPublicInterfacesOnly() const; bool javascriptCanPaste() const; bool dnsPrefetchEnabled() const; + bool pdfViewerEnabled() const; void setAutoLoadImages(bool on); void setJavascriptEnabled(bool on); @@ -166,6 +168,7 @@ public: void setWebRTCPublicInterfacesOnly(bool on); void setJavascriptCanPaste(bool on); void setDnsPrefetchEnabled(bool on); + void setPdfViewerEnabled(bool on); signals: void autoLoadImagesChanged(); @@ -198,6 +201,7 @@ signals: Q_REVISION(6) void webRTCPublicInterfacesOnlyChanged(); Q_REVISION(6) void javascriptCanPasteChanged(); Q_REVISION(7) void dnsPrefetchEnabledChanged(); + Q_REVISION(8) void pdfViewerEnabledChanged(); private: explicit QQuickWebEngineSettings(QQuickWebEngineSettings *parentSettings = 0); diff --git a/src/webengine/api/qquickwebenginetouchhandleprovider.cpp b/src/webengine/api/qquickwebenginetouchhandleprovider.cpp new file mode 100644 index 000000000..80f4727b6 --- /dev/null +++ b/src/webengine/api/qquickwebenginetouchhandleprovider.cpp @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickwebenginetouchhandleprovider_p_p.h" + +// static +QString QQuickWebEngineTouchHandleProvider::identifier() +{ + return QStringLiteral("touchhandle"); +} + +// static +QUrl QQuickWebEngineTouchHandleProvider::url(int orientation) +{ + return QUrl(QStringLiteral("image://%1/%2").arg(identifier(), QString::number(orientation))); +} + +QQuickWebEngineTouchHandleProvider::QQuickWebEngineTouchHandleProvider() + : QQuickImageProvider(QQuickImageProvider::Image) +{ +} + +QQuickWebEngineTouchHandleProvider::~QQuickWebEngineTouchHandleProvider() +{ +} + +void QQuickWebEngineTouchHandleProvider::init(const QMap<int, QImage> &images) +{ + if (!m_touchHandleMap.empty()) { + Q_ASSERT(images.size() == m_touchHandleMap.size()); + return; + } + + m_touchHandleMap.unite(images); +} + +QImage QQuickWebEngineTouchHandleProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize) +{ + Q_UNUSED(size); + Q_UNUSED(requestedSize); + + Q_ASSERT(m_touchHandleMap.contains(id.toInt())); + return m_touchHandleMap.value(id.toInt()); +} diff --git a/src/webengine/api/qquickwebenginetouchhandleprovider_p_p.h b/src/webengine/api/qquickwebenginetouchhandleprovider_p_p.h new file mode 100644 index 000000000..277436289 --- /dev/null +++ b/src/webengine/api/qquickwebenginetouchhandleprovider_p_p.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKWEBENGINETOUCHHANDLEPROVIDER_P_P_H +#define QQUICKWEBENGINETOUCHHANDLEPROVIDER_P_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 <QtQuick/QQuickImageProvider> +#include <QtWebEngine/private/qtwebengineglobal_p.h> + +QT_BEGIN_NAMESPACE + +class Q_WEBENGINE_PRIVATE_EXPORT QQuickWebEngineTouchHandleProvider : public QQuickImageProvider { +public: + static QString identifier(); + static QUrl url(int orientation); + + QQuickWebEngineTouchHandleProvider(); + ~QQuickWebEngineTouchHandleProvider(); + + void init(const QMap<int, QImage> &images); + virtual QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize); + +private: + QMap<int, QImage> m_touchHandleMap; +}; + + +QT_END_NAMESPACE + +#endif // QQUICKWEBENGINETOUCHHANDLEPROVIDER_P_P_H diff --git a/src/webengine/api/qquickwebengineview.cpp b/src/webengine/api/qquickwebengineview.cpp index 8097689ad..fca69121a 100644 --- a/src/webengine/api/qquickwebengineview.cpp +++ b/src/webengine/api/qquickwebengineview.cpp @@ -39,17 +39,18 @@ #include "qquickwebengineview_p.h" #include "qquickwebengineview_p_p.h" -#include "qtwebenginecoreglobal_p.h" #include "authentication_dialog_controller.h" #include "profile_adapter.h" #include "certificate_error_controller.h" #include "file_picker_controller.h" #include "javascript_dialog_controller.h" +#include "touch_selection_menu_controller.h" #include "qquickwebengineaction_p.h" #include "qquickwebengineaction_p_p.h" #include "qquickwebenginehistory_p.h" #include "qquickwebenginecertificateerror_p.h" +#include "qquickwebengineclientcertificateselection_p.h" #include "qquickwebenginecontextmenurequest_p.h" #include "qquickwebenginedialogrequests_p.h" #include "qquickwebenginefaviconprovider_p_p.h" @@ -59,6 +60,7 @@ #include "qquickwebengineprofile_p.h" #include "qquickwebenginesettings_p.h" #include "qquickwebenginescript_p.h" +#include "qquickwebenginetouchhandleprovider_p_p.h" #include "qwebenginequotarequest.h" #include "qwebengineregisterprotocolhandlerrequest.h" @@ -126,7 +128,6 @@ QQuickWebEngineViewPrivate::QQuickWebEngineViewPrivate() , m_webChannel(0) , m_webChannelWorld(0) , m_isBeingAdopted(false) - , m_dpiScale(1.0) , m_backgroundColor(Qt::white) , m_zoomFactor(1.0) , m_ui2Enabled(false) @@ -218,6 +219,7 @@ RenderWidgetHostViewQtDelegate *QQuickWebEngineViewPrivate::CreateRenderWidgetHo RenderWidgetHostViewQtDelegateQuick *quickDelegate = new RenderWidgetHostViewQtDelegateQuick(client, /*isPopup = */ true); if (hasWindowCapability) { RenderWidgetHostViewQtDelegateQuickWindow *wrapperWindow = new RenderWidgetHostViewQtDelegateQuickWindow(quickDelegate); + wrapperWindow->setVirtualParent(q); quickDelegate->setParentItem(wrapperWindow->contentItem()); return wrapperWindow; } @@ -300,9 +302,17 @@ void QQuickWebEngineViewPrivate::allowCertificateError(const QSharedPointer<Cert m_certificateErrorControllers.append(errorController); } -void QQuickWebEngineViewPrivate::selectClientCert(const QSharedPointer<ClientCertSelectController> &) +void QQuickWebEngineViewPrivate::selectClientCert(const QSharedPointer<ClientCertSelectController> &controller) { - // Doing nothing will free the select-controller and perform default continue. +#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) + Q_Q(QQuickWebEngineView); + QQuickWebEngineClientCertificateSelection *certSelection = new QQuickWebEngineClientCertificateSelection(controller); + // mark the object for gc by creating temporary jsvalue + qmlEngine(q)->newQObject(certSelection); + Q_EMIT q->selectClientCertificate(certSelection); +#else + Q_UNUSED(controller); +#endif } void QQuickWebEngineViewPrivate::runGeolocationPermissionRequest(const QUrl &url) @@ -311,6 +321,12 @@ void QQuickWebEngineViewPrivate::runGeolocationPermissionRequest(const QUrl &url Q_EMIT q->featurePermissionRequested(url, QQuickWebEngineView::Geolocation); } +void QQuickWebEngineViewPrivate::runUserNotificationPermissionRequest(const QUrl &url) +{ + Q_Q(QQuickWebEngineView); + Q_EMIT q->featurePermissionRequested(url, QQuickWebEngineView::Notifications); +} + void QQuickWebEngineViewPrivate::showColorDialog(QSharedPointer<ColorChooserController> controller) { Q_Q(QQuickWebEngineView); @@ -409,11 +425,6 @@ QRectF QQuickWebEngineViewPrivate::viewportRect() const return QRectF(q->x(), q->y(), q->width(), q->height()); } -qreal QQuickWebEngineViewPrivate::dpiScale() const -{ - return m_dpiScale; -} - QColor QQuickWebEngineViewPrivate::backgroundColor() const { return m_backgroundColor; @@ -1108,9 +1119,7 @@ void QQuickWebEngineViewPrivate::updateAdapter() adapter->setClient(this); if (wasInitialized) { if (!m_html.isEmpty()) - adapter->setContent(m_html.toUtf8(), defaultMimeType, m_url); - else if (m_url.isValid()) - adapter->load(m_url); + adapter->setContent(m_html.toUtf8(), defaultMimeType, activeUrl); else if (activeUrl.isValid()) adapter->load(activeUrl); else @@ -1156,12 +1165,12 @@ void QQuickWebEngineViewPrivate::didFindText(quint64 requestId, int matchCount) callback.call(args); } -void QQuickWebEngineViewPrivate::didPrintPage(quint64 requestId, const QByteArray &result) +void QQuickWebEngineViewPrivate::didPrintPage(quint64 requestId, QSharedPointer<QByteArray> result) { Q_Q(QQuickWebEngineView); QJSValue callback = m_callbacks.take(requestId); QJSValueList args; - args.append(qmlEngine(q)->toScriptValue(result)); + args.append(qmlEngine(q)->toScriptValue(*(result.data()))); callback.call(args); } @@ -1229,6 +1238,39 @@ void QQuickWebEngineViewPrivate::setToolTip(const QString &toolTipText) ui()->showToolTip(toolTipText); } +QtWebEngineCore::TouchHandleDrawableClient *QQuickWebEngineViewPrivate::createTouchHandle(const QMap<int, QImage> &images) +{ + return new QQuickWebEngineTouchHandle(ui(), images); +} + +void QQuickWebEngineViewPrivate::showTouchSelectionMenu(QtWebEngineCore::TouchSelectionMenuController *menuController, const QRect &selectionBounds, const QSize &handleSize) +{ + Q_UNUSED(handleSize); + + const int kSpacingBetweenButtons = 2; + const int kMenuButtonMinWidth = 63; + const int kMenuButtonMinHeight = 38; + + int buttonCount = menuController->buttonCount(); + if (buttonCount == 1) { + menuController->runContextMenu(); + return; + } + + int width = (kSpacingBetweenButtons * (buttonCount + 1)) + (kMenuButtonMinWidth * buttonCount); + int height = kMenuButtonMinHeight + kSpacingBetweenButtons; + int x = (selectionBounds.x() + selectionBounds.x() + selectionBounds.width() - width) / 2; + int y = selectionBounds.y() - height - 2; + + QRect bounds(x, y, width, height); + ui()->showTouchSelectionMenu(menuController, bounds, kSpacingBetweenButtons); +} + +void QQuickWebEngineViewPrivate::hideTouchSelectionMenu() +{ + ui()->hideTouchSelectionMenu(); +} + bool QQuickWebEngineView::isLoading() const { Q_D(const QQuickWebEngineView); @@ -1539,6 +1581,9 @@ void QQuickWebEngineView::grantFeaturePermission(const QUrl &securityOrigin, QQu WebContentsAdapterClient::MediaDesktopAudioCapture | WebContentsAdapterClient::MediaDesktopVideoCapture)); break; + case Notifications: + d_ptr->adapter->runUserNotificationRequestCallback(securityOrigin, granted); + break; default: Q_UNREACHABLE(); } @@ -2303,5 +2348,43 @@ bool QQuickContextMenuBuilder::isMenuItemEnabled(ContextMenuItem menuItem) Q_UNREACHABLE(); } + +QQuickWebEngineTouchHandle::QQuickWebEngineTouchHandle(QtWebEngineCore::UIDelegatesManager *ui, const QMap<int, QImage> &images) +{ + Q_ASSERT(ui); + m_item.reset(ui->createTouchHandle()); + + QQmlEngine *engine = qmlEngine(m_item.data()); + Q_ASSERT(engine); + QQuickWebEngineTouchHandleProvider *touchHandleProvider = + static_cast<QQuickWebEngineTouchHandleProvider *>(engine->imageProvider(QQuickWebEngineTouchHandleProvider::identifier())); + Q_ASSERT(touchHandleProvider); + touchHandleProvider->init(images); +} + +void QQuickWebEngineTouchHandle::setImage(int orientation) +{ + QUrl url = QQuickWebEngineTouchHandleProvider::url(orientation); + m_item->setProperty("source", url); +} + +void QQuickWebEngineTouchHandle::setBounds(const QRect &bounds) +{ + m_item->setProperty("x", bounds.x()); + m_item->setProperty("y", bounds.y()); + m_item->setProperty("width", bounds.width()); + m_item->setProperty("height", bounds.height()); +} + +void QQuickWebEngineTouchHandle::setVisible(bool visible) +{ + m_item->setProperty("visible", visible); +} + +void QQuickWebEngineTouchHandle::setOpacity(float opacity) +{ + m_item->setProperty("opacity", opacity); +} + QT_END_NAMESPACE diff --git a/src/webengine/api/qquickwebengineview_p.h b/src/webengine/api/qquickwebengineview_p.h index ae92b6df0..c851dcb8d 100644 --- a/src/webengine/api/qquickwebengineview_p.h +++ b/src/webengine/api/qquickwebengineview_p.h @@ -51,12 +51,11 @@ // We mean it. // -#include <QtWebEngineCore/private/qtwebenginecoreglobal_p.h> #include <QtWebEngine/private/qtwebengineglobal_p.h> -#include "qquickwebenginescript.h" #include <QQuickItem> #include <QtGui/qcolor.h> +#include "qquickwebenginescript.h" QT_BEGIN_NAMESPACE @@ -65,6 +64,7 @@ class QQuickContextMenuBuilder; class QQuickWebEngineAction; class QQuickWebEngineAuthenticationDialogRequest; class QQuickWebEngineCertificateError; +class QQuickWebEngineClientCertificateSelection; class QQuickWebEngineColorDialogRequest; class QQuickWebEngineContextMenuRequest; class QQuickWebEngineFaviconProvider; @@ -104,7 +104,7 @@ private: const bool m_toggleOn; }; -#define LATEST_WEBENGINEVIEW_REVISION 7 +#define LATEST_WEBENGINEVIEW_REVISION 9 class Q_WEBENGINE_PRIVATE_EXPORT QQuickWebEngineView : public QQuickItem { Q_OBJECT @@ -209,7 +209,8 @@ public: MediaAudioVideoCapture, Geolocation, DesktopVideoCapture, - DesktopAudioVideoCapture + DesktopAudioVideoCapture, + Notifications, }; Q_ENUM(Feature) @@ -550,6 +551,7 @@ Q_SIGNALS: Q_REVISION(7) void devToolsViewChanged(); Q_REVISION(7) void registerProtocolHandlerRequested(const QWebEngineRegisterProtocolHandlerRequest &request); Q_REVISION(8) void printRequested(); + Q_REVISION(9) void selectClientCertificate(QQuickWebEngineClientCertificateSelection *clientCertSelection); #if QT_CONFIG(webengine_testsupport) void testSupportChanged(); diff --git a/src/webengine/api/qquickwebengineview_p_p.h b/src/webengine/api/qquickwebengineview_p_p.h index 3b6300d5f..10fe5c2fd 100644 --- a/src/webengine/api/qquickwebengineview_p_p.h +++ b/src/webengine/api/qquickwebengineview_p_p.h @@ -53,6 +53,7 @@ #include "qquickwebengineview_p.h" #include "render_view_context_menu_qt.h" +#include "touch_handle_drawable_client.h" #include "web_contents_adapter_client.h" #include <QPointer> @@ -64,6 +65,8 @@ namespace QtWebEngineCore { class RenderWidgetHostViewQtDelegateQuick; +class TouchHandleDrawableClient; +class TouchSelectionMenuController; class UIDelegatesManager; class WebContentsAdapter; } @@ -76,6 +79,7 @@ class QQuickWebEngineContextMenuRequest; class QQuickWebEngineSettings; class QQuickWebEngineFaviconProvider; class QQuickWebEngineProfilePrivate; +class QQuickWebEngineTouchHandleProvider; QQuickWebEngineView::WebAction editorActionForKeyEvent(QKeyEvent* event); @@ -105,7 +109,6 @@ public: void selectionChanged() override { } void recentlyAudibleChanged(bool recentlyAudible) override; QRectF viewportRect() const override; - qreal dpiScale() const override; QColor backgroundColor() const override; void loadStarted(const QUrl &provisionalUrl, bool isErrorPage = false) override; void loadCommitted() override; @@ -128,7 +131,7 @@ public: void didFetchDocumentMarkup(quint64, const QString&) override { } void didFetchDocumentInnerText(quint64, const QString&) override { } void didFindText(quint64, int) override; - void didPrintPage(quint64 requestId, const QByteArray &result) override; + void didPrintPage(quint64 requestId, QSharedPointer<QByteArray>) 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; @@ -142,6 +145,7 @@ public: void allowCertificateError(const QSharedPointer<CertificateErrorController> &errorController) override; void selectClientCert(const QSharedPointer<ClientCertSelectController> &selectController) override; void runGeolocationPermissionRequest(QUrl const&) override; + void runUserNotificationPermissionRequest(QUrl const&) override; void renderProcessTerminated(RenderProcessTerminationStatus terminationStatus, int exitCode) override; void requestGeometryChange(const QRect &geometry, const QRect &frameGeometry) override; void updateScrollPosition(const QPointF &position) override; @@ -153,6 +157,9 @@ public: bool supportsDragging() const override; bool isEnabled() const override; void setToolTip(const QString &toolTipText) override; + QtWebEngineCore::TouchHandleDrawableClient *createTouchHandle(const QMap<int, QImage> &images) override; + void showTouchSelectionMenu(QtWebEngineCore::TouchSelectionMenuController *, const QRect &, const QSize &) override; + void hideTouchSelectionMenu() override; const QObject *holdingQObject() const override; ClientType clientType() override { return QtWebEngineCore::WebContentsAdapterClient::QmlClient; } @@ -212,7 +219,6 @@ public: private: QScopedPointer<QtWebEngineCore::UIDelegatesManager> m_uIDelegatesManager; QList<QQuickWebEngineScript *> m_userScripts; - qreal m_dpiScale; QColor m_backgroundColor; qreal m_zoomFactor; bool m_ui2Enabled; @@ -254,6 +260,19 @@ private: QObject *m_menu; }; +class Q_WEBENGINE_PRIVATE_EXPORT QQuickWebEngineTouchHandle : public QtWebEngineCore::TouchHandleDrawableClient { +public: + QQuickWebEngineTouchHandle(QtWebEngineCore::UIDelegatesManager *ui, const QMap<int, QImage> &images); + + void setImage(int orientation) override; + void setBounds(const QRect &bounds) override; + void setVisible(bool visible) override; + void setOpacity(float opacity) override; + +private: + QScopedPointer<QQuickItem> m_item; +}; + QT_END_NAMESPACE #endif // QQUICKWEBENGINEVIEW_P_P_H diff --git a/src/webengine/api/qtwebengineglobal.h b/src/webengine/api/qtwebengineglobal.h index 2d83be674..c2b33778a 100644 --- a/src/webengine/api/qtwebengineglobal.h +++ b/src/webengine/api/qtwebengineglobal.h @@ -41,6 +41,7 @@ #define QTWEBENGINEGLOBAL_H #include <QtCore/qglobal.h> +#include <QtWebEngine/qtwebengine-config.h> QT_BEGIN_NAMESPACE diff --git a/src/webengine/api/qtwebengineglobal_p.h b/src/webengine/api/qtwebengineglobal_p.h index 7058bef09..2d30f75b0 100644 --- a/src/webengine/api/qtwebengineglobal_p.h +++ b/src/webengine/api/qtwebengineglobal_p.h @@ -51,7 +51,9 @@ // We mean it. // -#include "qtwebengineglobal.h" +#include <QtWebEngine/qtwebengineglobal.h> +#include <QtCore/private/qglobal_p.h> +#include <QtWebEngine/private/qtwebengine-config_p.h> QT_BEGIN_NAMESPACE diff --git a/src/webengine/configure.json b/src/webengine/configure.json new file mode 100644 index 000000000..ca0e5c2fd --- /dev/null +++ b/src/webengine/configure.json @@ -0,0 +1,30 @@ +{ + "module": "webengine", + "depends": [ + "webenginecore-private" + ], + "condition": "module.webenginecore", + "features": { + "webengine-ui-delegates": { + "label": "UI Delegates", + "section": "WebEngine", + "output": [ "privateFeature" ] + }, + "webengine-testsupport": { + "label": "Test Support", + "autoDetect": "features.private_tests || call.isTestsInBuildParts", + "output": [ "privateFeature" ] + } + }, + "summary": [ + { + "section": "Qt WebEngineQml", + "condition": "features.webengine-qml", + "entries": [ + "webengine-ui-delegates", + "webengine-testsupport" + ] + } + ] +} + diff --git a/src/webengine/doc/qtwebengine.qdocconf b/src/webengine/doc/qtwebengine.qdocconf index 50f2e2ceb..be5db9c19 100644 --- a/src/webengine/doc/qtwebengine.qdocconf +++ b/src/webengine/doc/qtwebengine.qdocconf @@ -1,4 +1,5 @@ include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf) +include($QT_INSTALL_DOCS/config/exampleurl-qtwebengine.qdocconf) project = QtWebEngine description = Qt WebEngine Reference Documentation @@ -60,12 +61,14 @@ depends += qtcore \ qtwidgets headerdirs += .. \ - ../../core \ - ../../webenginewidgets + ../../core/api \ + ../../webenginewidgets/api sourcedirs += .. \ - ../../core/ \ - ../../webenginewidgets \ + ../../core/api \ + ../../core/doc \ + ../../webenginewidgets/api \ + ../../webenginewidgets/doc exampledirs += . \ ../../../examples \ @@ -84,4 +87,4 @@ navigation.qmltypespage = "Qt WebEngine QML Types" # \QWE macro expands to 'Qt WebEngine' without auto-linking anywhere. macro.QWE = "Qt \\WebEngine" -Cpp.ignoretokens += Q_WEBENGINE_EXPORT QWEBENGINEWIDGETS_EXPORT +Cpp.ignoretokens += Q_WEBENGINE_EXPORT Q_WEBENGINECORE_EXPORT QWEBENGINEWIDGETS_EXPORT diff --git a/src/webengine/doc/src/external-resources.qdoc b/src/webengine/doc/src/external-resources.qdoc index ba9823047..55f6a68a3 100644 --- a/src/webengine/doc/src/external-resources.qdoc +++ b/src/webengine/doc/src/external-resources.qdoc @@ -134,3 +134,8 @@ \externalpage https://developer.mozilla.org/en-US/docs/Web/API/Navigator/registerProtocolHandler \title registerProtocolHandler */ + +/*! + \externalpage https://www.w3.org/TR/notifications + \title Web Notifications API +*/ diff --git a/src/webengine/doc/src/qtwebengine-features.qdoc b/src/webengine/doc/src/qtwebengine-features.qdoc index 6522fb6f7..00b9cb496 100644 --- a/src/webengine/doc/src/qtwebengine-features.qdoc +++ b/src/webengine/doc/src/qtwebengine-features.qdoc @@ -44,12 +44,14 @@ \li \l{HTTP/2 Protocol} \li \l{Native Dialogs} \li \l{Pepper Plugin API} + \li \l{PDF File Viewing} \li \l{Print to PDF} \li \l{Process Models} \li \l{Spellchecker} \li \l{Touch} \li \l{View Source} \li \l{WebRTC} + \li \l{Web Notifications} \endlist \section1 Audio and Video Codecs @@ -124,7 +126,9 @@ so uniquely identifies the user and might violate privacy expectations. To activate support for client certificates, an application needs to listen to - the QWebEnginePage::selectClientCertificate signal and select one of the offered + the QWebEnginePage::selectClientCertificate or + \l{WebEnginePage::selectClientCertificate}{WebEnginePage.selectClientCertificate} + signals and select one of the offered certificates. For applications that can navigate to untrusted web sites, it is recommended to always give the user a choice before uniquely identifying them to a remote server. @@ -318,6 +322,21 @@ feature, the \c https://helpx.adobe.com/flash-player.html page can be opened in the browser. + \section1 PDF File Viewing + + \QWE supports viewing PDF documents by navigating to them. This feature uses the Chromium + extensions API and PDF viewer plugin to display the PDF documents. + It can be tested in \l{WebEngine Widgets Simple Browser Example}{Simple Browser} or + \l{WebEngine Quick Nano Browser}{Nano Browser}. + + Loading plugins needs to be enabled using QWebEngineSettings::PluginsEnabled or + WebEngineSettings::pluginsEnabled in order to use this feature. + + This feature can be turned on (default) or off via the QWebEngineSettings::PdfViewerEnabled or + WebEngineSettings::pdfViewerEnabled setting. + + Support for this feature was added in Qt 5.13.0. + \section1 Print to PDF \QWE supports printing a web page to a PDF file. For more @@ -511,4 +530,13 @@ This feature can be tested by setting up a webcam or microphone and then opening \c https://test.webrtc.org/ in \l{WebEngine Widgets Simple Browser Example}{Simple Browser} or \l{WebEngine Quick Nano Browser}{Nano Browser}. + + \section1 Web Notifications + + Qt WebEngine supports JavaScript \l{Web Notifications API}. + The application has to explicitly allow the feature by using + QWebEnginePage::Notifications or \l{WebEngineView::Feature} + {WebEngineView.Notifications}. + + Support for this feature was added in Qt 5.13.0. */ diff --git a/src/webengine/doc/src/qtwebengine-overview.qdoc b/src/webengine/doc/src/qtwebengine-overview.qdoc index 8feb38eca..6aa1af89e 100644 --- a/src/webengine/doc/src/qtwebengine-overview.qdoc +++ b/src/webengine/doc/src/qtwebengine-overview.qdoc @@ -89,8 +89,8 @@ \l{https://chromium.googlesource.com/chromium/src/+/master/docs/chromium_browser_vs_google_chrome.md}{overview} that is part of the documentation in the \l {Chromium Project} upstream source tree. - This version of \QWE is based on Chromium version 69.0.3497.128, with - additional security fixes from newer versions. + This version of \QWE is based on Chromium version 73.0.3683, with additional security + fixes from newer versions. \section2 Qt WebEngine Process @@ -238,14 +238,18 @@ are automatically retrieved from the system. Settings from an installed QNetworkProxyFactory will be ignored, though. - Not all properties of QNetworkProxy are supported by \QWE. That is, - QNetworkProxy::type(), QNetworkProxy::hostName() and QNetworkProxy::port() are taken into - account. All other proxy settings such as QNetworkProxy::rawHeader(), QNetworkProxy::user(), or - QNetworkProxy::password() are ignored. + In case QNetworkProxy::user() and QNetworkProxy::password() are set, these credentials + will be automatically used for proxy authentication. It is up to the user to provide valid + credentials, since there is no error handling callback. - If a proxy requires authentication, QWebEnginePage::proxyAuthenticationRequired is emitted. + If no credentials are set with QNetworkProxy, but the proxy requires authentication, + QWebEnginePage::proxyAuthenticationRequired is emitted. For Qt Quick, a dialog is shown. + Not all properties of QNetworkProxy are supported by \QWE. That is, + QNetworkProxy::type(), QNetworkProxy::hostName() and QNetworkProxy::port() are taken into + account. All other proxy settings such as QNetworkProxy::rawHeader() are ignored. + \section1 High DPI Support To support High DPI devices, it is recommended that the application attribute diff --git a/src/webengine/doc/src/qtwebengine-qmlmodule.qdoc b/src/webengine/doc/src/qtwebengine-qmlmodule.qdoc index 5e172087d..540d74035 100644 --- a/src/webengine/doc/src/qtwebengine-qmlmodule.qdoc +++ b/src/webengine/doc/src/qtwebengine-qmlmodule.qdoc @@ -26,7 +26,7 @@ ****************************************************************************/ /*! - \qmlmodule QtWebEngine 1.8 + \qmlmodule QtWebEngine 1.9 \title Qt WebEngine QML Types \brief Provides QML types for rendering web content within a QML application. \ingroup qtwebengine-modules @@ -36,7 +36,7 @@ your .qml file: \badcode - import QtWebEngine 1.8 + import QtWebEngine 1.9 \endcode To link against the module, add the following QT variable to your qmake .pro diff --git a/src/webengine/doc/src/webengineview_lgpl.qdoc b/src/webengine/doc/src/webengineview_lgpl.qdoc index a4f07ddd9..7efe447ac 100644 --- a/src/webengine/doc/src/webengineview_lgpl.qdoc +++ b/src/webengine/doc/src/webengineview_lgpl.qdoc @@ -870,6 +870,8 @@ (Added in Qt 5.10) \value DesktopAudioVideoCapture Both audio and video output capture. (Added in Qt 5.10) + \value WebEnginView.Notifications + Web notifications for the end-user. \sa featurePermissionRequested(), grantFeaturePermission() */ @@ -1488,3 +1490,19 @@ \sa printToPdf */ + +/*! + \qmlsignal WebEngineView::selectClientCertificate(WebEngineClientCertificateSelection clientCertificateSelection) + \since QtWebEngine 1.9 + + This signal is emitted when a web site requests an SSL client certificate, and one or more were + found in the system's client certificate store. + + Handling the signal is asynchronous, and loading will be waiting until a certificate is selected, + or the last copy of \a clientCertificateSelection is destroyed. + + If the signal is not handled, \a clientCertificateSelection is automatically destroyed, and loading + will continue without a client certificate. + + \sa WebEngineClientCertificateSelection +*/ diff --git a/src/webengine/module.pro b/src/webengine/module.pro new file mode 100644 index 000000000..49a1086b2 --- /dev/null +++ b/src/webengine/module.pro @@ -0,0 +1,94 @@ +include($$QTWEBENGINE_OUT_ROOT/src/webengine/qtwebengine-config.pri) +QT_FOR_CONFIG += webengine-private + +TARGET = QtWebEngine +MODULE = webengine + +# For our export macros +DEFINES += QT_BUILD_WEBENGINE_LIB + +QT += qml quick webenginecore +QT_PRIVATE += quick-private gui-private core-private webenginecore-private + +QMAKE_DOCS = $$PWD/doc/qtwebengine.qdocconf + +INCLUDEPATH += $$PWD api ../core ../core/api + +SOURCES = \ + api/qquickwebengineaction.cpp \ + api/qquickwebenginecertificateerror.cpp \ + api/qquickwebengineclientcertificateselection.cpp \ + api/qquickwebenginecontextmenurequest.cpp \ + api/qquickwebenginedialogrequests.cpp \ + api/qquickwebenginedownloaditem.cpp \ + api/qquickwebenginehistory.cpp \ + api/qquickwebenginefaviconprovider.cpp \ + api/qquickwebengineloadrequest.cpp \ + api/qquickwebenginenavigationrequest.cpp \ + api/qquickwebenginenewviewrequest.cpp \ + api/qquickwebengineprofile.cpp \ + api/qquickwebenginescript.cpp \ + api/qquickwebenginesettings.cpp \ + api/qquickwebenginesingleton.cpp \ + api/qquickwebenginetouchhandleprovider.cpp \ + api/qquickwebengineview.cpp \ + api/qtwebengineglobal.cpp \ + render_widget_host_view_qt_delegate_quick.cpp \ + render_widget_host_view_qt_delegate_quickwindow.cpp \ + ui_delegates_manager.cpp + +HEADERS = \ + api/qtwebengineglobal.h \ + api/qtwebengineglobal_p.h \ + api/qquickwebengineaction_p.h \ + api/qquickwebengineaction_p_p.h \ + api/qquickwebenginecertificateerror_p.h \ + api/qquickwebengineclientcertificateselection_p.h \ + api/qquickwebenginecontextmenurequest_p.h \ + api/qquickwebenginedialogrequests_p.h \ + api/qquickwebenginedownloaditem_p.h \ + api/qquickwebenginedownloaditem_p_p.h \ + api/qquickwebenginehistory_p.h \ + api/qquickwebenginefaviconprovider_p_p.h \ + api/qquickwebengineloadrequest_p.h \ + api/qquickwebenginenavigationrequest_p.h \ + api/qquickwebenginenewviewrequest_p.h \ + api/qquickwebengineprofile.h \ + api/qquickwebengineprofile_p.h \ + api/qquickwebenginescript.h \ + api/qquickwebenginescript_p.h \ + api/qquickwebenginesettings_p.h \ + api/qquickwebenginesingleton_p.h \ + api/qquickwebenginetouchhandleprovider_p_p.h \ + api/qquickwebengineview_p.h \ + api/qquickwebengineview_p_p.h \ + render_widget_host_view_qt_delegate_quick.h \ + render_widget_host_view_qt_delegate_quickwindow.h \ + ui_delegates_manager.h + +qtConfig(webengine-testsupport) { + QT_PRIVATE += testlib + SOURCES += api/qquickwebenginetestsupport.cpp + HEADERS += api/qquickwebenginetestsupport_p.h +} + +!build_pass { + python = $$pythonPathForShell() + chromium_attributions.commands = \ + cd $$shell_quote($$shell_path($$PWD/../3rdparty)) && \ + $$python chromium/tools/licenses.py \ + --file-template ../../tools/about_credits.tmpl \ + --entry-template ../../tools/about_credits_entry.tmpl credits \ + $$shell_quote($$shell_path($$OUT_PWD/chromium_attributions.qdoc)) + chromium_attributions.CONFIG += phony + + QMAKE_EXTRA_TARGETS += chromium_attributions + + prepare_docs { + prepare_docs.depends += chromium_attributions + } else { + html_docs.depends += chromium_attributions + } +} + +load(qt_module) diff --git a/src/webengine/plugin/plugin.cpp b/src/webengine/plugin/plugin.cpp index 84a12c930..a332288d4 100644 --- a/src/webengine/plugin/plugin.cpp +++ b/src/webengine/plugin/plugin.cpp @@ -40,22 +40,24 @@ #include <QtQml/qqmlextensionplugin.h> #include <QtWebEngine/QQuickWebEngineProfile> -#include "qquickwebenginecertificateerror_p.h" -#include "qquickwebenginecontextmenurequest_p.h" -#include "qquickwebenginedialogrequests_p.h" -#include "qquickwebenginedownloaditem_p.h" -#include "qquickwebenginehistory_p.h" -#include "qquickwebenginefaviconprovider_p_p.h" -#include "qquickwebengineloadrequest_p.h" -#include "qquickwebenginenavigationrequest_p.h" -#include "qquickwebenginenewviewrequest_p.h" -#include "qquickwebenginesettings_p.h" -#include "qquickwebenginesingleton_p.h" -#include "qquickwebengineview_p.h" -#include "qquickwebengineaction_p.h" -#include "qwebenginequotarequest.h" -#include "qwebengineregisterprotocolhandlerrequest.h" -#include "qtwebengineversion.h" +#include <QtWebEngine/private/qquickwebenginecertificateerror_p.h> +#include <QtWebEngine/private/qquickwebengineclientcertificateselection_p.h> +#include <QtWebEngine/private/qquickwebenginecontextmenurequest_p.h> +#include <QtWebEngine/private/qquickwebenginedialogrequests_p.h> +#include <QtWebEngine/private/qquickwebenginedownloaditem_p.h> +#include <QtWebEngine/private/qquickwebenginehistory_p.h> +#include <QtWebEngine/private/qquickwebenginefaviconprovider_p_p.h> +#include <QtWebEngine/private/qquickwebengineloadrequest_p.h> +#include <QtWebEngine/private/qquickwebenginenavigationrequest_p.h> +#include <QtWebEngine/private/qquickwebenginenewviewrequest_p.h> +#include <QtWebEngine/private/qquickwebenginesettings_p.h> +#include <QtWebEngine/private/qquickwebenginesingleton_p.h> +#include <QtWebEngine/private/qquickwebenginetouchhandleprovider_p_p.h> +#include <QtWebEngine/private/qquickwebengineview_p.h> +#include <QtWebEngine/private/qquickwebengineaction_p.h> +#include <QtWebEngineCore/qwebenginenotification.h> +#include <QtWebEngineCore/qwebenginequotarequest.h> +#include <QtWebEngineCore/qwebengineregisterprotocolhandlerrequest.h> QT_BEGIN_NAMESPACE @@ -73,6 +75,7 @@ public: { Q_UNUSED(uri); engine->addImageProvider(QQuickWebEngineFaviconProvider::identifier(), new QQuickWebEngineFaviconProvider); + engine->addImageProvider(QQuickWebEngineTouchHandleProvider::identifier(), new QQuickWebEngineTouchHandleProvider); } void registerTypes(const char *uri) override @@ -91,11 +94,13 @@ public: qmlRegisterType<QQuickWebEngineView, 6>(uri, 1, 6, "WebEngineView"); qmlRegisterType<QQuickWebEngineView, 7>(uri, 1, 7, "WebEngineView"); qmlRegisterType<QQuickWebEngineView, 8>(uri, 1, 8, "WebEngineView"); + qmlRegisterType<QQuickWebEngineView, 9>(uri, 1, 9, "WebEngineView"); qmlRegisterType<QQuickWebEngineProfile>(uri, 1, 1, "WebEngineProfile"); qmlRegisterType<QQuickWebEngineProfile, 1>(uri, 1, 2, "WebEngineProfile"); qmlRegisterType<QQuickWebEngineProfile, 2>(uri, 1, 3, "WebEngineProfile"); qmlRegisterType<QQuickWebEngineProfile, 3>(uri, 1, 4, "WebEngineProfile"); qmlRegisterType<QQuickWebEngineProfile, 4>(uri, 1, 5, "WebEngineProfile"); + qmlRegisterType<QQuickWebEngineProfile, 5>(uri, 1, 9, "WebEngineProfile"); qmlRegisterType<QQuickWebEngineScript>(uri, 1, 1, "WebEngineScript"); qmlRegisterUncreatableType<QQuickWebEngineCertificateError>(uri, 1, 1, "WebEngineCertificateError", msgUncreatableType("WebEngineCertificateError")); qmlRegisterUncreatableType<QQuickWebEngineDownloadItem>(uri, 1, 1, "WebEngineDownloadItem", @@ -116,14 +121,15 @@ public: tr("Cannot create a separate instance of WebEngineDownloadItem")); qmlRegisterUncreatableType<QQuickWebEngineNewViewRequest>(uri, 1, 1, "WebEngineNewViewRequest", msgUncreatableType("WebEngineNewViewRequest")); qmlRegisterUncreatableType<QQuickWebEngineNewViewRequest, 1>(uri, 1, 5, "WebEngineNewViewRequest", tr("Cannot create separate instance of WebEngineNewViewRequest")); - qmlRegisterUncreatableType<QQuickWebEngineSettings>(uri, 1, 1, "WebEngineSettings", tr("Cannot create a separate instance of WebEngineSettings")); - qmlRegisterUncreatableType<QQuickWebEngineSettings, 1>(uri, 1, 2, "WebEngineSettings", tr("Cannot create a separate instance of WebEngineSettings")); - qmlRegisterUncreatableType<QQuickWebEngineSettings, 2>(uri, 1, 3, "WebEngineSettings", tr("Cannot create a separate instance of WebEngineSettings")); - qmlRegisterUncreatableType<QQuickWebEngineSettings, 3>(uri, 1, 4, "WebEngineSettings", tr("Cannot create a separate instance of WebEngineSettings")); - qmlRegisterUncreatableType<QQuickWebEngineSettings, 4>(uri, 1, 5, "WebEngineSettings", tr("Cannot create a separate instance of WebEngineSettings")); - qmlRegisterUncreatableType<QQuickWebEngineSettings, 5>(uri, 1, 6, "WebEngineSettings", tr("Cannot create a separate instance of WebEngineSettings")); - qmlRegisterUncreatableType<QQuickWebEngineSettings, 6>(uri, 1, 7, "WebEngineSettings", tr("Cannot create a separate instance of WebEngineSettings")); - qmlRegisterUncreatableType<QQuickWebEngineSettings, 7>(uri, 1, 8, "WebEngineSettings", tr("Cannot create a separate instance of WebEngineSettings")); + qmlRegisterUncreatableType<QQuickWebEngineSettings>(uri, 1, 1, "WebEngineSettings", msgUncreatableType("WebEngineSettings")); + qmlRegisterUncreatableType<QQuickWebEngineSettings, 1>(uri, 1, 2, "WebEngineSettings", msgUncreatableType("WebEngineSettings")); + qmlRegisterUncreatableType<QQuickWebEngineSettings, 2>(uri, 1, 3, "WebEngineSettings", msgUncreatableType("WebEngineSettings")); + qmlRegisterUncreatableType<QQuickWebEngineSettings, 3>(uri, 1, 4, "WebEngineSettings", msgUncreatableType("WebEngineSettings")); + qmlRegisterUncreatableType<QQuickWebEngineSettings, 4>(uri, 1, 5, "WebEngineSettings", msgUncreatableType("WebEngineSettings")); + qmlRegisterUncreatableType<QQuickWebEngineSettings, 5>(uri, 1, 6, "WebEngineSettings", msgUncreatableType("WebEngineSettings")); + qmlRegisterUncreatableType<QQuickWebEngineSettings, 6>(uri, 1, 7, "WebEngineSettings", msgUncreatableType("WebEngineSettings")); + qmlRegisterUncreatableType<QQuickWebEngineSettings, 7>(uri, 1, 8, "WebEngineSettings", msgUncreatableType("WebEngineSettings")); + qmlRegisterUncreatableType<QQuickWebEngineSettings, 8>(uri, 1, 9, "WebEngineSettings", msgUncreatableType("WebEngineSettings")); qmlRegisterSingletonType<QQuickWebEngineSingleton>(uri, 1, 1, "WebEngine", webEngineSingletonProvider); qmlRegisterUncreatableType<QQuickWebEngineHistory>(uri, 1, 1, "NavigationHistory", tr("Cannot create a separate instance of NavigationHistory")); @@ -153,6 +159,13 @@ public: qmlRegisterUncreatableType<QWebEngineRegisterProtocolHandlerRequest>(uri, 1, 7, "RegisterProtocolHandlerRequest", msgUncreatableType("RegisterProtocolHandlerRequest")); qmlRegisterUncreatableType<QQuickWebEngineAction>(uri, 1, 8, "WebEngineAction", msgUncreatableType("WebEngineAction")); +#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) + qmlRegisterUncreatableType<QQuickWebEngineClientCertificateSelection>(uri, 1, 9, "WebEngineClientCertificateSelection", + msgUncreatableType("WebEngineClientCertificateSelection")); + qmlRegisterUncreatableType<QQuickWebEngineClientCertificateOption>(uri, 1, 9, "WebEngineClientCertificateOption", + msgUncreatableType("WebEngineClientCertificateOption")); +#endif + qmlRegisterUncreatableType<QWebEngineNotification>(uri, 1, 9, "WebEngineNotification", msgUncreatableType("WebEngineNotification")); } private: diff --git a/src/webengine/plugin/plugin.pro b/src/webengine/plugin/plugin.pro index b6652fa26..0c1310de3 100644 --- a/src/webengine/plugin/plugin.pro +++ b/src/webengine/plugin/plugin.pro @@ -1,13 +1,12 @@ CXX_MODULE = qml TARGET = qtwebengineplugin TARGETPATH = QtWebEngine -IMPORT_VERSION = 1.8 +IMPORT_VERSION = 1.9 -QT += webengine qml quick +QT += qml quick QT_PRIVATE += core-private webenginecore-private webengine-private -INCLUDEPATH += $$QTWEBENGINE_ROOT/src/core $$QTWEBENGINE_ROOT/src/core/api $$QTWEBENGINE_ROOT/src/webengine $$QTWEBENGINE_ROOT/src/webengine/api $$QTWEBENGINE_ROOT/include/QtWebEngine - SOURCES = plugin.cpp +QMAKE_QMLPLUGINDUMP_FLAGS = -defaultplatform load(qml_plugin) diff --git a/src/webengine/plugin/plugins.qmltypes b/src/webengine/plugin/plugins.qmltypes index 1f295ac57..0037861e5 100644 --- a/src/webengine/plugin/plugins.qmltypes +++ b/src/webengine/plugin/plugins.qmltypes @@ -4,7 +4,7 @@ import QtQuick.tooling 1.2 // It is used for QML tooling purposes only. // // This file was auto-generated by: -// 'qmlplugindump -defaultplatform -dependencies dependencies.json -nonrelocatable QtWebEngine 1.8' +// 'qmlplugindump -nonrelocatable -defaultplatform -dependencies dependencies.json QtWebEngine 1.9' Module { dependencies: ["QtQuick 2.8"] @@ -80,6 +80,46 @@ Module { Method { name: "rejectCertificate" } } Component { + name: "QQuickWebEngineClientCertificateOption" + prototype: "QObject" + exports: ["QtWebEngine/WebEngineClientCertificateOption 1.9"] + isCreatable: false + exportMetaObjectRevisions: [0] + Property { name: "issuer"; type: "string"; isReadonly: true } + Property { name: "subject"; type: "string"; isReadonly: true } + Property { name: "effectiveDate"; type: "QDateTime"; isReadonly: true } + Property { name: "expiryDate"; type: "QDateTime"; isReadonly: true } + Property { name: "isSelfSigned"; type: "bool"; isReadonly: true } + Method { name: "select" } + } + Component { + name: "QQuickWebEngineClientCertificateSelection" + prototype: "QObject" + exports: ["QtWebEngine/WebEngineClientCertificateSelection 1.9"] + isCreatable: false + exportMetaObjectRevisions: [0] + Property { name: "host"; type: "QUrl"; isReadonly: true } + Property { + name: "certificates" + type: "QQuickWebEngineClientCertificateOption" + isList: true + isReadonly: true + } + Method { + name: "select" + Parameter { name: "idx"; type: "int" } + } + Method { + name: "select" + Parameter { + name: "certificate" + type: "const QQuickWebEngineClientCertificateOption" + isPointer: true + } + } + Method { name: "selectNone" } + } + Component { name: "QQuickWebEngineColorDialogRequest" prototype: "QObject" exports: ["QtWebEngine/ColorDialogRequest 1.4"] @@ -437,9 +477,10 @@ Module { "QtWebEngine/WebEngineProfile 1.2", "QtWebEngine/WebEngineProfile 1.3", "QtWebEngine/WebEngineProfile 1.4", - "QtWebEngine/WebEngineProfile 1.5" + "QtWebEngine/WebEngineProfile 1.5", + "QtWebEngine/WebEngineProfile 1.9" ] - exportMetaObjectRevisions: [0, 1, 2, 3, 4] + exportMetaObjectRevisions: [0, 1, 2, 3, 4, 5] Enum { name: "HttpCacheType" values: { @@ -474,9 +515,13 @@ Module { isList: true isReadonly: true } + Property { name: "useForGlobalCertificateVerification"; revision: 5; type: "bool" } + Property { name: "downloadPath"; revision: 5; type: "string" } Signal { name: "httpAcceptLanguageChanged"; revision: 1 } Signal { name: "spellCheckLanguagesChanged"; revision: 3 } Signal { name: "spellCheckEnabledChanged"; revision: 3 } + Signal { name: "useForGlobalCertificateVerificationChanged"; revision: 5 } + Signal { name: "downloadPathChanged"; revision: 5 } Signal { name: "downloadRequested" Parameter { name: "download"; type: "QQuickWebEngineDownloadItem"; isPointer: true } @@ -485,6 +530,11 @@ Module { name: "downloadFinished" Parameter { name: "download"; type: "QQuickWebEngineDownloadItem"; isPointer: true } } + Signal { + name: "presentNotification" + revision: 5 + Parameter { name: "notification"; type: "QWebEngineNotification"; isPointer: true } + } Method { name: "clearHttpCache"; revision: 2 } } Component { @@ -617,6 +667,7 @@ Module { Property { name: "webRTCPublicInterfacesOnly"; revision: 6; type: "bool" } Property { name: "javascriptCanPaste"; revision: 6; type: "bool" } Property { name: "dnsPrefetchEnabled"; revision: 7; type: "bool" } + Property { name: "pdfViewerEnabled"; revision: 8; type: "bool" } Signal { name: "fullScreenSupportEnabledChanged"; revision: 1 } Signal { name: "screenCaptureEnabledChanged"; revision: 2 } Signal { name: "webGLEnabledChanged"; revision: 2 } @@ -634,6 +685,7 @@ Module { Signal { name: "webRTCPublicInterfacesOnlyChanged"; revision: 6 } Signal { name: "javascriptCanPasteChanged"; revision: 6 } Signal { name: "dnsPrefetchEnabledChanged"; revision: 7 } + Signal { name: "pdfViewerEnabledChanged"; revision: 8 } } Component { name: "QQuickWebEngineSingleton" @@ -664,9 +716,10 @@ Module { "QtWebEngine/WebEngineView 1.5", "QtWebEngine/WebEngineView 1.6", "QtWebEngine/WebEngineView 1.7", - "QtWebEngine/WebEngineView 1.8" + "QtWebEngine/WebEngineView 1.8", + "QtWebEngine/WebEngineView 1.9" ] - exportMetaObjectRevisions: [0, 1, 2, 3, 4, 5, 6, 7, 8] + exportMetaObjectRevisions: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] Enum { name: "NavigationRequestAction" values: { @@ -723,7 +776,8 @@ Module { "MediaAudioVideoCapture": 2, "Geolocation": 3, "DesktopVideoCapture": 4, - "DesktopAudioVideoCapture": 5 + "DesktopAudioVideoCapture": 5, + "Notifications": 6 } } Enum { @@ -1131,6 +1185,15 @@ Module { Parameter { name: "request"; type: "QWebEngineRegisterProtocolHandlerRequest" } } Signal { name: "printRequested"; revision: 8 } + Signal { + name: "selectClientCertificate" + revision: 9 + Parameter { + name: "clientCertSelection" + type: "QQuickWebEngineClientCertificateSelection" + isPointer: true + } + } Method { name: "runJavaScript" Parameter { type: "string" } @@ -1257,6 +1320,32 @@ Module { } } Component { + name: "QWebEngineNotification" + prototype: "QObject" + exports: ["QtWebEngine/WebEngineNotification 1.9"] + isCreatable: false + exportMetaObjectRevisions: [0] + Enum { + name: "Direction" + values: { + "LeftToRight": 0, + "RightToLeft": 1, + "DirectionAuto": 2 + } + } + Property { name: "origin"; type: "QUrl"; isReadonly: true } + Property { name: "icon"; type: "QIcon"; isReadonly: true } + Property { name: "title"; type: "string"; isReadonly: true } + Property { name: "message"; type: "string"; isReadonly: true } + Property { name: "tag"; type: "string"; isReadonly: true } + Property { name: "language"; type: "string"; isReadonly: true } + Property { name: "direction"; type: "Direction"; isReadonly: true } + Signal { name: "closed" } + Method { name: "show" } + Method { name: "click" } + Method { name: "close" } + } + Component { name: "QWebEngineQuotaRequest" exports: ["QtWebEngine/QuotaRequest 1.7"] isCreatable: false diff --git a/src/webengine/render_widget_host_view_qt_delegate_quick.cpp b/src/webengine/render_widget_host_view_qt_delegate_quick.cpp index 8aaf4c714..55ec19fc9 100644 --- a/src/webengine/render_widget_host_view_qt_delegate_quick.cpp +++ b/src/webengine/render_widget_host_view_qt_delegate_quick.cpp @@ -99,19 +99,26 @@ void RenderWidgetHostViewQtDelegateQuick::initAsPopup(const QRect &r) setVisible(true); } -QRectF RenderWidgetHostViewQtDelegateQuick::screenRect() const -{ - QPointF pos = mapToScene(QPointF(0,0)); - return QRectF(pos.x(), pos.y(), width(), height()); +QRectF RenderWidgetHostViewQtDelegateQuick::viewGeometry() const +{ + // Transform the entire rect to find the correct top left corner. + const QPointF p1 = mapToGlobal(mapFromScene(QPointF(0, 0))); + const QPointF p2 = mapToGlobal(mapFromScene(QPointF(width(), height()))); + QRectF geometry = QRectF(p1, p2).normalized(); + // But keep the size untransformed to behave like other QQuickItems. +#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) + geometry.setSize(size()); +#else + geometry.setSize(QSizeF(width(), height())); +#endif + return geometry; } -QRectF RenderWidgetHostViewQtDelegateQuick::contentsRect() const +QRect RenderWidgetHostViewQtDelegateQuick::windowGeometry() const { - QPointF scenePoint = mapToScene(QPointF(0, 0)); - QPointF screenPos; - if (window()) - screenPos = window()->mapToGlobal(scenePoint.toPoint()); - return QRectF(screenPos.x(), screenPos.y(), width(), height()); + if (!window()) + return QRect(); + return window()->frameGeometry(); } void RenderWidgetHostViewQtDelegateQuick::setKeyboardFocus() @@ -322,16 +329,7 @@ void RenderWidgetHostViewQtDelegateQuick::inputMethodEvent(QInputMethodEvent *ev void RenderWidgetHostViewQtDelegateQuick::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) { QQuickItem::geometryChanged(newGeometry, oldGeometry); - - if (window()) { - const QPointF globalPos = QQuickItem::mapToGlobal(position()); - if (globalPos != m_lastGlobalPos) { - m_lastGlobalPos = globalPos; - m_client->windowBoundsChanged(); - } - } - - m_client->notifyResize(); + m_client->visualPropertiesChanged(); } void RenderWidgetHostViewQtDelegateQuick::itemChange(ItemChange change, const ItemChangeData &value) @@ -347,8 +345,7 @@ void RenderWidgetHostViewQtDelegateQuick::itemChange(ItemChange change, const It if (!m_isPopup) m_windowConnections.append(connect(value.window, SIGNAL(closing(QQuickCloseEvent *)), SLOT(onHide()))); } - - m_client->windowChanged(); + m_client->visualPropertiesChanged(); } else if (change == QQuickItem::ItemVisibleHasChanged) { if (!m_isPopup && !value.boolValue) onHide(); @@ -362,9 +359,7 @@ QSGNode *RenderWidgetHostViewQtDelegateQuick::updatePaintNode(QSGNode *oldNode, void RenderWidgetHostViewQtDelegateQuick::onWindowPosChanged() { - if (window()) - m_lastGlobalPos = QQuickItem::mapToGlobal(position()); - m_client->windowBoundsChanged(); + m_client->visualPropertiesChanged(); } void RenderWidgetHostViewQtDelegateQuick::onHide() diff --git a/src/webengine/render_widget_host_view_qt_delegate_quick.h b/src/webengine/render_widget_host_view_qt_delegate_quick.h index d4d64804a..00158b3ac 100644 --- a/src/webengine/render_widget_host_view_qt_delegate_quick.h +++ b/src/webengine/render_widget_host_view_qt_delegate_quick.h @@ -59,8 +59,8 @@ public: ~RenderWidgetHostViewQtDelegateQuick(); void initAsPopup(const QRect&) override; - QRectF screenRect() const override; - QRectF contentsRect() const override; + QRectF viewGeometry() const override; + QRect windowGeometry() const override; void setKeyboardFocus() override; bool hasKeyboardFocus() override; void lockMouse() override; @@ -113,7 +113,6 @@ private: RenderWidgetHostViewQtDelegateClient *m_client; QList<QMetaObject::Connection> m_windowConnections; bool m_isPopup; - QPointF m_lastGlobalPos; QQuickWebEngineView *m_view = nullptr; }; diff --git a/src/webengine/render_widget_host_view_qt_delegate_quickwindow.cpp b/src/webengine/render_widget_host_view_qt_delegate_quickwindow.cpp index d3c88148e..3648df3c1 100644 --- a/src/webengine/render_widget_host_view_qt_delegate_quickwindow.cpp +++ b/src/webengine/render_widget_host_view_qt_delegate_quickwindow.cpp @@ -44,32 +44,59 @@ namespace QtWebEngineCore { -RenderWidgetHostViewQtDelegateQuickWindow::RenderWidgetHostViewQtDelegateQuickWindow(RenderWidgetHostViewQtDelegate *realDelegate) +RenderWidgetHostViewQtDelegateQuickWindow::RenderWidgetHostViewQtDelegateQuickWindow(RenderWidgetHostViewQtDelegateQuick *realDelegate) : m_realDelegate(realDelegate) + , m_virtualParent(nullptr) { - setFlags(Qt::ToolTip | Qt::FramelessWindowHint | Qt::WindowDoesNotAcceptFocus); + setFlags(Qt::Tool | Qt::FramelessWindowHint | Qt::WindowDoesNotAcceptFocus); } RenderWidgetHostViewQtDelegateQuickWindow::~RenderWidgetHostViewQtDelegateQuickWindow() { } +void RenderWidgetHostViewQtDelegateQuickWindow::setVirtualParent(QQuickItem *virtualParent) +{ + Q_ASSERT(virtualParent); + m_virtualParent = virtualParent; +} + +static inline QRectF mapRectToGlobal(const QQuickItem *item, const QRectF &rect) +{ + const QPointF p1 = item->mapToGlobal(rect.topLeft()); + const QPointF p2 = item->mapToGlobal(rect.bottomRight()); + return QRectF(p1, p2).normalized(); +} + +static inline QRectF mapRectFromGlobal(const QQuickItem *item, const QRectF &rect) +{ + const QPointF p1 = item->mapFromGlobal(rect.topLeft()); + const QPointF p2 = item->mapFromGlobal(rect.bottomRight()); + return QRectF(p1, p2).normalized(); +} + void RenderWidgetHostViewQtDelegateQuickWindow::initAsPopup(const QRect &screenRect) { - m_realDelegate->initAsPopup(QRect(QPoint(0, 0), screenRect.size())); - setGeometry(screenRect); + QRectF popupRect(screenRect); + popupRect = mapRectFromGlobal(m_virtualParent, popupRect); + popupRect = m_virtualParent->mapRectToScene(popupRect); + popupRect = mapRectToGlobal(m_virtualParent, popupRect); + + m_realDelegate->initAsPopup(QRect(QPoint(0, 0), popupRect.size().toSize())); + popupRect.setSize(screenRect.size()); + setGeometry(popupRect.toAlignedRect()); raise(); show(); } -QRectF RenderWidgetHostViewQtDelegateQuickWindow::screenRect() const +QRectF RenderWidgetHostViewQtDelegateQuickWindow::viewGeometry() const { - return QRectF(x(), y(), width(), height()); + return geometry(); } -QRectF RenderWidgetHostViewQtDelegateQuickWindow::contentsRect() const +QRect RenderWidgetHostViewQtDelegateQuickWindow::windowGeometry() const { - return geometry(); + return frameGeometry(); } void RenderWidgetHostViewQtDelegateQuickWindow::show() @@ -138,7 +165,12 @@ void RenderWidgetHostViewQtDelegateQuickWindow::resize(int width, int height) void RenderWidgetHostViewQtDelegateQuickWindow::move(const QPoint &screenPos) { - QQuickWindow::setPosition(screenPos); + QRectF popupRect(screenPos, size()); + popupRect = mapRectFromGlobal(m_virtualParent, popupRect); + popupRect = m_virtualParent->mapRectToScene(popupRect); + popupRect = mapRectToGlobal(m_virtualParent, popupRect); + + QQuickWindow::setPosition(popupRect.topLeft().toPoint()); } } // namespace QtWebEngineCore diff --git a/src/webengine/render_widget_host_view_qt_delegate_quickwindow.h b/src/webengine/render_widget_host_view_qt_delegate_quickwindow.h index 36e4ddd8a..ab583bd63 100644 --- a/src/webengine/render_widget_host_view_qt_delegate_quickwindow.h +++ b/src/webengine/render_widget_host_view_qt_delegate_quickwindow.h @@ -52,12 +52,12 @@ namespace QtWebEngineCore { class RenderWidgetHostViewQtDelegateQuickWindow : public QQuickWindow , public RenderWidgetHostViewQtDelegate { public: - RenderWidgetHostViewQtDelegateQuickWindow(RenderWidgetHostViewQtDelegate *realDelegate); + RenderWidgetHostViewQtDelegateQuickWindow(RenderWidgetHostViewQtDelegateQuick *realDelegate); ~RenderWidgetHostViewQtDelegateQuickWindow(); void initAsPopup(const QRect&) override; - QRectF screenRect() const override; - QRectF contentsRect() const override; + QRectF viewGeometry() const override; + QRect windowGeometry() const override; void setKeyboardFocus() override {} bool hasKeyboardFocus() override { return false; } void lockMouse() override {} @@ -80,8 +80,11 @@ public: void setClearColor(const QColor &) override { } bool copySurface(const QRect &, const QSize &, QImage &) override { return false; } + void setVirtualParent(QQuickItem *virtualParent); + private: - QScopedPointer<RenderWidgetHostViewQtDelegate> m_realDelegate; + QScopedPointer<RenderWidgetHostViewQtDelegateQuick> m_realDelegate; + QQuickItem *m_virtualParent; }; } // namespace QtWebEngineCore diff --git a/src/webengine/plugin/testsupport/plugin.cpp b/src/webengine/testsupport/plugin.cpp index d5c43a859..7a1e73d8b 100644 --- a/src/webengine/plugin/testsupport/plugin.cpp +++ b/src/webengine/testsupport/plugin.cpp @@ -39,7 +39,7 @@ #include <QtQml> -#include "qquickwebenginetestsupport_p.h" +#include <QtWebEngine/private/qquickwebenginetestsupport_p.h> QT_BEGIN_NAMESPACE diff --git a/src/webengine/testsupport/plugins.qmltypes b/src/webengine/testsupport/plugins.qmltypes new file mode 100644 index 000000000..12c763724 --- /dev/null +++ b/src/webengine/testsupport/plugins.qmltypes @@ -0,0 +1,73 @@ +import QtQuick.tooling 1.2 + +// This file describes the plugin-supplied types contained in the library. +// It is used for QML tooling purposes only. +// +// This file was auto-generated by: +// 'qmlplugindump -nonrelocatable QtWebEngine.testsupport 1.0' + +Module { + dependencies: ["QtQuick 2.0"] + Component { name: "QPlatformInputContext"; prototype: "QObject" } + Component { + name: "QQuickWebEngineErrorPage" + prototype: "QObject" + exports: ["QtWebEngine.testsupport/WebEngineErrorPage 1.0"] + isCreatable: false + exportMetaObjectRevisions: [0] + Signal { + name: "loadingChanged" + Parameter { name: "loadRequest"; type: "QQuickWebEngineLoadRequest"; isPointer: true } + } + } + Component { + name: "QQuickWebEngineTestEvent" + prototype: "QObject" + exports: ["QtWebEngine.testsupport/WebEngineTestEvent 1.0"] + isCreatable: false + exportMetaObjectRevisions: [0] + Method { + name: "mouseMultiClick" + type: "bool" + Parameter { name: "item"; type: "QObject"; isPointer: true } + Parameter { name: "x"; type: "double" } + Parameter { name: "y"; type: "double" } + Parameter { name: "clickCount"; type: "int" } + } + } + Component { + name: "QQuickWebEngineTestInputContext" + prototype: "QPlatformInputContext" + exports: ["QtWebEngine.testsupport/TestInputContext 1.0"] + isCreatable: false + exportMetaObjectRevisions: [0] + Method { name: "create" } + Method { name: "release" } + } + Component { + name: "QQuickWebEngineTestSupport" + prototype: "QObject" + exports: ["QtWebEngine.testsupport/WebEngineTestSupport 1.0"] + exportMetaObjectRevisions: [0] + Property { + name: "errorPage" + type: "QQuickWebEngineErrorPage" + isReadonly: true + isPointer: true + } + Property { + name: "testInputContext" + type: "QQuickWebEngineTestInputContext" + isReadonly: true + isPointer: true + } + Property { + name: "testEvent" + type: "QQuickWebEngineTestEvent" + isReadonly: true + isPointer: true + } + Signal { name: "windowCloseRejected" } + Signal { name: "loadVisuallyCommitted" } + } +} diff --git a/src/webengine/plugin/testsupport/qmldir b/src/webengine/testsupport/qmldir index 7fff80251..7fff80251 100644 --- a/src/webengine/plugin/testsupport/qmldir +++ b/src/webengine/testsupport/qmldir diff --git a/src/webengine/plugin/testsupport/testsupport.pro b/src/webengine/testsupport/testsupport.pro index 2804635f8..a24796675 100644 --- a/src/webengine/plugin/testsupport/testsupport.pro +++ b/src/webengine/testsupport/testsupport.pro @@ -3,11 +3,9 @@ TARGET = qtwebenginetestsupportplugin TARGETPATH = QtWebEngine/testsupport IMPORT_VERSION = 1.0 -QT += webengine qml quick +QT += qml quick QT_PRIVATE += webengine-private gui-private -INCLUDEPATH += $$QTWEBENGINE_ROOT/src/core $$QTWEBENGINE_ROOT/src/webengine $$QTWEBENGINE_ROOT/src/webengine/api - SOURCES = plugin.cpp load(qml_plugin) diff --git a/src/webengine/ui/TouchHandle.qml b/src/webengine/ui/TouchHandle.qml new file mode 100644 index 000000000..76a93829e --- /dev/null +++ b/src/webengine/ui/TouchHandle.qml @@ -0,0 +1,42 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.5 + +Image { } diff --git a/src/webengine/ui/TouchSelectionMenu.qml b/src/webengine/ui/TouchSelectionMenu.qml new file mode 100644 index 000000000..7cf16b554 --- /dev/null +++ b/src/webengine/ui/TouchSelectionMenu.qml @@ -0,0 +1,175 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.5 +import QtQuick.Layouts 1.3 + +Rectangle { + id: menu + + signal cutTriggered + signal copyTriggered + signal pasteTriggered + signal contextMenuTriggered + + property bool isCutEnabled: false + property bool isCopyEnabled: false + property bool isPasteEnabled: false + + property color borderColor: "darkGray" + property color bgColor: "white" + + radius: 4 + border.color: borderColor + color: borderColor + antialiasing: true + + RowLayout { + anchors.fill: parent + spacing: parent.border.width + anchors.margins: parent.border.width + + Rectangle { + Layout.fillHeight: true + Layout.fillWidth: true + radius: menu.radius + color: bgColor + visible: isCutEnabled + + Text { + id: cutText + anchors.centerIn: parent + text: "Cut" + } + + MouseArea { + anchors.fill: parent + onPressed: { + parent.color = borderColor; + cutText.color = "white"; + } + onReleased: { + parent.color = bgColor; + cutText.color = "black"; + cutTriggered(); + } + } + } + + Rectangle { + Layout.fillHeight: true + Layout.fillWidth: true + radius: menu.radius + color: bgColor + visible: isCopyEnabled + + Text { + id: copyText + anchors.centerIn: parent + text: "Copy" + } + + MouseArea { + anchors.fill: parent + onPressed: { + parent.color = borderColor; + copyText.color = "white"; + } + onReleased: { + parent.color = bgColor; + copyText.color = "black"; + copyTriggered(); + } + } + } + + Rectangle { + Layout.fillHeight: true + Layout.fillWidth: true + radius: menu.radius + color: bgColor + visible: isPasteEnabled + + Text { + id: pasteText + anchors.centerIn: parent + text: "Paste" + } + + MouseArea { + anchors.fill: parent + onPressed: { + parent.color = borderColor; + pasteText.color = "white"; + } + onReleased: { + parent.color = bgColor; + pasteText.color = "black"; + pasteTriggered(); + } + } + } + + Rectangle { + Layout.fillHeight: true + Layout.fillWidth: true + radius: menu.radius + color: bgColor + + Text { + id: contextMenuText + anchors.centerIn: parent + text: "..." + } + + MouseArea { + anchors.fill: parent + onPressed: { + parent.color = borderColor; + contextMenuText.color = "white"; + } + onReleased: { + parent.color = bgColor; + contextMenuText.color = "black"; + contextMenuTriggered(); + } + } + } + } +} diff --git a/src/webengine/ui/ui.pro b/src/webengine/ui/ui.pro index eb6bf435c..69f754e0c 100644 --- a/src/webengine/ui/ui.pro +++ b/src/webengine/ui/ui.pro @@ -13,6 +13,8 @@ QML_FILES += \ Menu.qml \ MenuItem.qml \ MenuSeparator.qml \ - ToolTip.qml + ToolTip.qml \ + TouchHandle.qml \ + TouchSelectionMenu.qml load(qml_module) diff --git a/src/webengine/ui_delegates_manager.cpp b/src/webengine/ui_delegates_manager.cpp index 7e49bc77d..2f371efd5 100644 --- a/src/webengine/ui_delegates_manager.cpp +++ b/src/webengine/ui_delegates_manager.cpp @@ -44,6 +44,7 @@ #include <color_chooser_controller.h> #include <file_picker_controller.h> #include <javascript_dialog_controller.h> +#include <touch_selection_menu_controller.h> #include <web_contents_adapter_client.h> #include <QFileInfo> @@ -54,6 +55,7 @@ #include <QCursor> #include <QList> #include <QScreen> +#include <QTimer> #include <QGuiApplication> // Uncomment for QML debugging @@ -62,7 +64,7 @@ namespace QtWebEngineCore { #define NO_SEPARATOR -#if defined(Q_OS_WIN) +#if defined(Q_CC_MSVC) && !defined(Q_CC_CLANG) #define FILE_NAME_CASE_STATEMENT(TYPE, COMPONENT) \ case UIDelegatesManager::TYPE:\ return QString::fromLatin1(#TYPE ##".qml"); @@ -125,6 +127,7 @@ const char *defaultPropertyName(QObject *obj) UIDelegatesManager::UIDelegatesManager(QQuickWebEngineView *view) : m_view(view) , m_toolTip(nullptr) + , m_touchSelectionMenu(nullptr) FOR_EACH_COMPONENT_TYPE(COMPONENT_MEMBER_INIT, NO_SEPARATOR) { } @@ -321,7 +324,7 @@ void UIDelegatesManager::showDialog(QSharedPointer<JavaScriptDialogController> d return; } - QQmlComponent *dialogComponent = Q_NULLPTR; + QQmlComponent *dialogComponent = nullptr; switch (dialogComponentType) { FOR_EACH_COMPONENT_TYPE(ASSIGN_DIALOG_COMPONENT_DATA_CASE_STATEMENT, NO_SEPARATOR) default: @@ -568,6 +571,82 @@ void UIDelegatesManager::showToolTip(const QString &text) QMetaObject::invokeMethod(m_toolTip.data(), "open"); } +QQuickItem *UIDelegatesManager::createTouchHandle() +{ + if (!ensureComponentLoaded(TouchHandle)) + return nullptr; + + QQmlContext *context = qmlContext(m_view); + QObject *touchHandle = touchHandleComponent->beginCreate(context); + QQuickItem *item = qobject_cast<QQuickItem *>(touchHandle); + Q_ASSERT(item); + item->setParentItem(m_view); + touchHandleComponent->completeCreate(); + + return item; +} + +void UIDelegatesManager::showTouchSelectionMenu(QtWebEngineCore::TouchSelectionMenuController *menuController, const QRect &bounds, const int spacing) +{ + if (!ensureComponentLoaded(TouchSelectionMenu)) + return; + + QQmlContext *context = qmlContext(m_view); + m_touchSelectionMenu.reset(touchSelectionMenuComponent->beginCreate(context)); + if (QQuickItem *item = qobject_cast<QQuickItem *>(m_touchSelectionMenu.data())) + item->setParentItem(m_view); + m_touchSelectionMenu->setParent(m_view); + + QQmlProperty(m_touchSelectionMenu.data(), QStringLiteral("width")).write(bounds.width()); + QQmlProperty(m_touchSelectionMenu.data(), QStringLiteral("height")).write(bounds.height()); + QQmlProperty(m_touchSelectionMenu.data(), QStringLiteral("x")).write(bounds.x()); + QQmlProperty(m_touchSelectionMenu.data(), QStringLiteral("y")).write(bounds.y()); + QQmlProperty(m_touchSelectionMenu.data(), QStringLiteral("border.width")).write(spacing); + + // Cut button + bool cutEnabled = menuController->isCommandEnabled(TouchSelectionMenuController::Cut); + QQmlProperty(m_touchSelectionMenu.data(), QStringLiteral("isCutEnabled")).write(cutEnabled); + if (cutEnabled) { + QQmlProperty cutSignal(m_touchSelectionMenu.data(), QStringLiteral("onCutTriggered")); + CHECK_QML_SIGNAL_PROPERTY(cutSignal, touchSelectionMenuComponent->url()); + int cutIndex = menuController->metaObject()->indexOfSlot("cut()"); + QObject::connect(m_touchSelectionMenu.data(), cutSignal.method(), menuController, menuController->metaObject()->method(cutIndex)); + } + + // Copy button + bool copyEnabled = menuController->isCommandEnabled(TouchSelectionMenuController::Copy); + QQmlProperty(m_touchSelectionMenu.data(), QStringLiteral("isCopyEnabled")).write(copyEnabled); + if (copyEnabled) { + QQmlProperty copySignal(m_touchSelectionMenu.data(), QStringLiteral("onCopyTriggered")); + CHECK_QML_SIGNAL_PROPERTY(copySignal, touchSelectionMenuComponent->url()); + int copyIndex = menuController->metaObject()->indexOfSlot("copy()"); + QObject::connect(m_touchSelectionMenu.data(), copySignal.method(), menuController, menuController->metaObject()->method(copyIndex)); + } + + // Paste button + bool pasteEnabled = menuController->isCommandEnabled(TouchSelectionMenuController::Paste); + QQmlProperty(m_touchSelectionMenu.data(), QStringLiteral("isPasteEnabled")).write(pasteEnabled); + if (pasteEnabled) { + QQmlProperty pasteSignal(m_touchSelectionMenu.data(), QStringLiteral("onPasteTriggered")); + CHECK_QML_SIGNAL_PROPERTY(pasteSignal, touchSelectionMenuComponent->url()); + int pasteIndex = menuController->metaObject()->indexOfSlot("paste()"); + QObject::connect(m_touchSelectionMenu.data(), pasteSignal.method(), menuController, menuController->metaObject()->method(pasteIndex)); + } + + // Context menu button + QQmlProperty contextMenuSignal(m_touchSelectionMenu.data(), QStringLiteral("onContextMenuTriggered")); + CHECK_QML_SIGNAL_PROPERTY(contextMenuSignal, touchSelectionMenuComponent->url()); + int contextMenuIndex = menuController->metaObject()->indexOfSlot("runContextMenu()"); + QObject::connect(m_touchSelectionMenu.data(), contextMenuSignal.method(), menuController, menuController->metaObject()->method(contextMenuIndex)); + + touchSelectionMenuComponent->completeCreate(); +} + +void UIDelegatesManager::hideTouchSelectionMenu() +{ + QTimer::singleShot(0, m_view, [this] { m_touchSelectionMenu.reset(); }); +} + UI2DelegatesManager::UI2DelegatesManager(QQuickWebEngineView *view) : UIDelegatesManager(view) { diff --git a/src/webengine/ui_delegates_manager.h b/src/webengine/ui_delegates_manager.h index 18457e4ed..4b6e291b2 100644 --- a/src/webengine/ui_delegates_manager.h +++ b/src/webengine/ui_delegates_manager.h @@ -61,6 +61,8 @@ F(FilePicker, filePicker) SEPARATOR \ F(AuthenticationDialog, authenticationDialog) SEPARATOR \ F(ToolTip, toolTip) SEPARATOR \ + F(TouchHandle, touchHandle) SEPARATOR \ + F(TouchSelectionMenu, touchSelectionMenu) SEPARATOR \ #define COMMA_SEPARATOR , #define SEMICOLON_SEPARATOR ; @@ -81,6 +83,7 @@ namespace QtWebEngineCore { class AuthenticationDialogController; class JavaScriptDialogController; class FilePickerController; +class TouchSelectionMenuController; const char *defaultPropertyName(QObject *obj); @@ -110,6 +113,9 @@ public: void showFilePicker(QSharedPointer<FilePickerController>); virtual void showMenu(QObject *menu); void showToolTip(const QString &text); + QQuickItem *createTouchHandle(); + void showTouchSelectionMenu(TouchSelectionMenuController *, const QRect &, const int spacing); + void hideTouchSelectionMenu(); protected: bool ensureComponentLoaded(ComponentType); @@ -117,6 +123,7 @@ protected: QQuickWebEngineView *m_view; QScopedPointer<QObject> m_toolTip; QStringList m_importDirs; + QScopedPointer<QObject> m_touchSelectionMenu; FOR_EACH_COMPONENT_TYPE(MEMBER_DECLARATION, SEMICOLON_SEPARATOR) diff --git a/src/webengine/webengine.pro b/src/webengine/webengine.pro index 418ade9a8..23668229e 100644 --- a/src/webengine/webengine.pro +++ b/src/webengine/webengine.pro @@ -1,89 +1,19 @@ -include($$QTWEBENGINE_OUT_ROOT/src/core/qtwebenginecore-config.pri) # workaround for QTBUG-68093 -QT_FOR_CONFIG += webenginecore-private +TEMPLATE = subdirs -TARGET = QtWebEngine +qml_module.file = module.pro +qml_plugin.file = plugin/plugin.pro -# For our export macros -DEFINES += QT_BUILD_WEBENGINE_LIB +qml_plugin.depends = qml_module -QT += qml quick webenginecore -QT_PRIVATE += quick-private gui-private core-private webenginecore-private - -QMAKE_DOCS = $$PWD/doc/qtwebengine.qdocconf - -INCLUDEPATH += $$PWD api ../core ../core/api - -SOURCES = \ - api/qquickwebengineaction.cpp \ - api/qquickwebenginecertificateerror.cpp \ - api/qquickwebenginecontextmenurequest.cpp \ - api/qquickwebenginedialogrequests.cpp \ - api/qquickwebenginedownloaditem.cpp \ - api/qquickwebenginehistory.cpp \ - api/qquickwebenginefaviconprovider.cpp \ - api/qquickwebengineloadrequest.cpp \ - api/qquickwebenginenavigationrequest.cpp \ - api/qquickwebenginenewviewrequest.cpp \ - api/qquickwebengineprofile.cpp \ - api/qquickwebenginescript.cpp \ - api/qquickwebenginesettings.cpp \ - api/qquickwebenginesingleton.cpp \ - api/qquickwebengineview.cpp \ - api/qtwebengineglobal.cpp \ - render_widget_host_view_qt_delegate_quick.cpp \ - render_widget_host_view_qt_delegate_quickwindow.cpp \ - ui_delegates_manager.cpp - -HEADERS = \ - api/qtwebengineglobal.h \ - api/qtwebengineglobal_p.h \ - api/qquickwebengineaction_p.h \ - api/qquickwebengineaction_p_p.h \ - api/qquickwebenginecertificateerror_p.h \ - api/qquickwebenginecontextmenurequest_p.h \ - api/qquickwebenginedialogrequests_p.h \ - api/qquickwebenginedownloaditem_p.h \ - api/qquickwebenginedownloaditem_p_p.h \ - api/qquickwebenginehistory_p.h \ - api/qquickwebenginefaviconprovider_p_p.h \ - api/qquickwebengineloadrequest_p.h \ - api/qquickwebenginenavigationrequest_p.h \ - api/qquickwebenginenewviewrequest_p.h \ - api/qquickwebengineprofile.h \ - api/qquickwebengineprofile_p.h \ - api/qquickwebenginescript.h \ - api/qquickwebenginescript_p.h \ - api/qquickwebenginesettings_p.h \ - api/qquickwebenginesingleton_p.h \ - api/qquickwebengineview_p.h \ - api/qquickwebengineview_p_p.h \ - render_widget_host_view_qt_delegate_quick.h \ - render_widget_host_view_qt_delegate_quickwindow.h \ - ui_delegates_manager.h +SUBDIRS += qml_module qml_plugin qtConfig(webengine-testsupport) { - QT_PRIVATE += testlib - SOURCES += api/qquickwebenginetestsupport.cpp - HEADERS += api/qquickwebenginetestsupport_p.h + testsupport_plugin.file = testsupport/testsupport.pro + testsupport_plugin.depends = qml_module + SUBDIRS += testsupport_plugin } -!build_pass { - python = $$pythonPathForShell() - chromium_attributions.commands = \ - cd $$shell_quote($$shell_path($$PWD/../3rdparty)) && \ - $$python chromium/tools/licenses.py \ - --file-template ../../tools/about_credits.tmpl \ - --entry-template ../../tools/about_credits_entry.tmpl credits \ - $$shell_quote($$shell_path($$OUT_PWD/chromium_attributions.qdoc)) - chromium_attributions.CONFIG += phony - - QMAKE_EXTRA_TARGETS += chromium_attributions - - prepare_docs { - prepare_docs.depends += chromium_attributions - } else { - html_docs.depends += chromium_attributions - } +qtConfig(webengine-ui-delegates) { + SUBDIRS += ui \ + ui2 } - -load(qt_module) diff --git a/src/webenginewidgets/api/qwebenginenotificationpresenter.cpp b/src/webenginewidgets/api/qwebenginenotificationpresenter.cpp new file mode 100644 index 000000000..667605c37 --- /dev/null +++ b/src/webenginewidgets/api/qwebenginenotificationpresenter.cpp @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwebenginenotificationpresenter_p.h" + +#include <QApplication> +#include <QSystemTrayIcon> + +QT_BEGIN_NAMESPACE + +DefaultNotificationPresenter::DefaultNotificationPresenter(QObject *parent) : QObject(parent) +{ +#ifndef QT_NO_SYSTEMTRAYICON + m_systemTrayIcon = new QSystemTrayIcon(this); + connect(m_systemTrayIcon, &QSystemTrayIcon::messageClicked, this, &DefaultNotificationPresenter::messageClicked); +#endif +} + +DefaultNotificationPresenter::~DefaultNotificationPresenter() +{ +} + +void DefaultNotificationPresenter::show(std::unique_ptr<QWebEngineNotification> notification) +{ + Q_ASSERT(notification); + if (m_activeNotification) { + m_activeNotification->close(); + m_activeNotification->disconnect(this); + } + + m_activeNotification = std::move(notification); + +#ifndef QT_NO_SYSTEMTRAYICON + if (m_activeNotification && m_systemTrayIcon) { + m_systemTrayIcon->setIcon(qApp->windowIcon()); + m_systemTrayIcon->show(); + QImage notificationIconImage = m_activeNotification->icon(); + m_notificationIcon = QIcon(QPixmap::fromImage(std::move(notificationIconImage), Qt::NoFormatConversion)); + if (!m_notificationIcon.isNull()) + m_systemTrayIcon->showMessage(m_activeNotification->title(), m_activeNotification->message(), m_notificationIcon); + else + m_systemTrayIcon->showMessage(m_activeNotification->title(), m_activeNotification->message()); + m_activeNotification->show(); + connect(m_activeNotification.get(), &QWebEngineNotification::closed, this, &DefaultNotificationPresenter::closeNotification); + } +#endif +} + +void DefaultNotificationPresenter::messageClicked() +{ + if (m_activeNotification) + m_activeNotification->click(); +} + +void DefaultNotificationPresenter::closeNotification() +{ +#ifndef QT_NO_SYSTEMTRAYICON + const QWebEngineNotification *canceled = static_cast<const QWebEngineNotification *>(QObject::sender()); + if (m_systemTrayIcon && canceled->matches(m_activeNotification.get())) + m_systemTrayIcon->hide(); +#endif +} + +void defaultNotificationPresenter(std::unique_ptr<QWebEngineNotification> notification) +{ + static DefaultNotificationPresenter *presenter = nullptr; + if (!presenter) + presenter = new DefaultNotificationPresenter(); + presenter->show(std::move(notification)); +} + + +QT_END_NAMESPACE diff --git a/src/webenginewidgets/api/qwebenginenotificationpresenter_p.h b/src/webenginewidgets/api/qwebenginenotificationpresenter_p.h new file mode 100644 index 000000000..49d774806 --- /dev/null +++ b/src/webenginewidgets/api/qwebenginenotificationpresenter_p.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWEBENGINENOTIFICATIONPRESENTER_P_H +#define QWEBENGINENOTIFICATIONPRESENTER_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 <QtWebEngineCore/QWebEngineNotification> + +#include <QtCore/QObject> +#include <QtGui/QIcon> + +#include <memory> + +QT_BEGIN_NAMESPACE + +class QSystemTrayIcon; + +class DefaultNotificationPresenter : public QObject { + Q_OBJECT +public: + DefaultNotificationPresenter(QObject *parent = nullptr); + virtual ~DefaultNotificationPresenter(); + + void show(std::unique_ptr<QWebEngineNotification> notification); + +private Q_SLOTS: + void messageClicked(); + void closeNotification(); + +private: + QSystemTrayIcon *m_systemTrayIcon; + QIcon m_notificationIcon; + std::unique_ptr<QWebEngineNotification> m_activeNotification; +}; + +void defaultNotificationPresenter(std::unique_ptr<QWebEngineNotification> notification); + +QT_END_NAMESPACE + +#endif // QWEBENGINENOTIFICATIONPRESENTER_P_H diff --git a/src/webenginewidgets/api/qwebenginepage.cpp b/src/webenginewidgets/api/qwebenginepage.cpp index aeed6ce85..7b66ac876 100644 --- a/src/webenginewidgets/api/qwebenginepage.cpp +++ b/src/webenginewidgets/api/qwebenginepage.cpp @@ -48,12 +48,13 @@ #include "file_picker_controller.h" #include "javascript_dialog_controller.h" #if QT_CONFIG(webengine_printing_and_pdf) -#include "printing/pdfium_document_wrapper_qt.h" +#include "printer_worker.h" #endif #include "qwebenginecertificateerror.h" #include "qwebenginefullscreenrequest.h" #include "qwebenginehistory.h" #include "qwebenginehistory_p.h" +#include "qwebenginenotification.h" #include "qwebengineprofile.h" #include "qwebengineprofile_p.h" #include "qwebenginequotarequest.h" @@ -62,6 +63,7 @@ #include "qwebenginesettings.h" #include "qwebengineview.h" #include "qwebengineview_p.h" +#include "user_notification_controller.h" #include "render_widget_host_view_qt_delegate_widget.h" #include "web_contents_adapter.h" #include "web_engine_settings.h" @@ -94,6 +96,7 @@ #include <QMimeData> #if QT_CONFIG(webengine_printing_and_pdf) #include <QPrinter> +#include <QThread> #endif #include <QStandardPaths> #include <QStyle> @@ -106,89 +109,6 @@ using namespace QtWebEngineCore; static const int MaxTooltipLength = 1024; -#if QT_CONFIG(webengine_printing_and_pdf) -static bool printPdfDataOnPrinter(const QByteArray& data, QPrinter& printer) -{ - if (!data.size()) { - qWarning("Failure to print on printer %ls: Print result data is empty.", - qUtf16Printable(printer.printerName())); - return false; - } - - QSize pageSize = printer.pageRect().size(); - PdfiumDocumentWrapperQt pdfiumWrapper(data.constData(), data.size(), pageSize); - - int toPage = printer.toPage(); - int fromPage = printer.fromPage(); - bool ascendingOrder = true; - - if (fromPage == 0 && toPage == 0) { - fromPage = 1; - toPage = pdfiumWrapper.pageCount(); - } - fromPage = qMax(1, fromPage); - toPage = qMin(pdfiumWrapper.pageCount(), toPage); - - if (printer.pageOrder() == QPrinter::LastPageFirst) { - qSwap(fromPage, toPage); - ascendingOrder = false; - } - - int pageCopies = 1; - int documentCopies = 1; - - if (!printer.supportsMultipleCopies()) - documentCopies = printer.copyCount(); - - if (printer.collateCopies()) { - pageCopies = documentCopies; - documentCopies = 1; - } - - QPainter painter; - if (!painter.begin(&printer)) { - qWarning("Failure to print on printer %ls: Could not open printer for painting.", - qUtf16Printable(printer.printerName())); - return false; - } - - for (int printedDocuments = 0; printedDocuments < documentCopies; printedDocuments++) { - int currentPageIndex = fromPage; - while (true) { - for (int printedPages = 0; printedPages < pageCopies; printedPages++) { - if (printer.printerState() == QPrinter::Aborted - || printer.printerState() == QPrinter::Error) - return false; - - QImage currentImage = pdfiumWrapper.pageAsQImage(currentPageIndex - 1); - if (currentImage.isNull()) - return false; - - // Painting operations are automatically clipped to the bounds of the drawable part of the page. - painter.drawImage(QRect(0, 0, pageSize.width(), pageSize.height()), currentImage, currentImage.rect()); - if (printedPages < pageCopies - 1) - printer.newPage(); - } - - if (currentPageIndex == toPage) - break; - - if (ascendingOrder) - currentPageIndex++; - else - currentPageIndex--; - - printer.newPage(); - } - if (printedDocuments < documentCopies - 1) - printer.newPage(); - } - painter.end(); - - return true; -} -#endif // QT_CONFIG(webengine_printing_and_pdf) - static QWebEnginePage::WebWindowType toWindowType(WebContentsAdapterClient::WindowOpenDisposition disposition) { switch (disposition) { @@ -241,6 +161,7 @@ QWebEnginePagePrivate::QWebEnginePagePrivate(QWebEngineProfile *_profile) , webChannelWorldId(QWebEngineScript::MainWorld) , defaultAudioMuted(false) , defaultZoomFactor(1.0) + , requestInterceptor(nullptr) #if QT_CONFIG(webengine_printing_and_pdf) , currentPrinter(nullptr) #endif @@ -254,7 +175,6 @@ QWebEnginePagePrivate::QWebEnginePagePrivate(QWebEngineProfile *_profile) wasShownTimer.setSingleShot(true); QObject::connect(&wasShownTimer, &QTimer::timeout, [this](){ ensureInitialized(); - wasShown(); }); profile->d_ptr->addWebContentsAdapterClient(this); @@ -262,6 +182,8 @@ QWebEnginePagePrivate::QWebEnginePagePrivate(QWebEngineProfile *_profile) QWebEnginePagePrivate::~QWebEnginePagePrivate() { + if (requestInterceptor) + profile->d_ptr->profileAdapter()->removePageRequestInterceptor(); delete history; delete settings; profile->d_ptr->removeWebContentsAdapterClient(this); @@ -292,6 +214,9 @@ void QWebEnginePagePrivate::initializationFinished() if (!qFuzzyCompare(adapter->currentZoomFactor(), defaultZoomFactor)) adapter->setZoomFactor(defaultZoomFactor); + if (view && view->isVisible()) + adapter->wasShown(); + scriptCollection.d->initializationFinished(adapter); m_isBeingAdopted = false; @@ -335,7 +260,7 @@ void QWebEnginePagePrivate::didUpdateTargetURL(const QUrl &hoveredUrl) void QWebEnginePagePrivate::selectionChanged() { Q_Q(QWebEnginePage); - Q_EMIT q->selectionChanged(); + QTimer::singleShot(0, q, &QWebEnginePage::selectionChanged); } void QWebEnginePagePrivate::recentlyAudibleChanged(bool recentlyAudible) @@ -349,11 +274,6 @@ QRectF QWebEnginePagePrivate::viewportRect() const return view ? view->rect() : QRectF(); } -qreal QWebEnginePagePrivate::dpiScale() const -{ - return 1.0; -} - QColor QWebEnginePagePrivate::backgroundColor() const { return m_backgroundColor; @@ -502,19 +422,35 @@ void QWebEnginePagePrivate::didFindText(quint64 requestId, int matchCount) m_callbacks.invoke(requestId, matchCount > 0); } -void QWebEnginePagePrivate::didPrintPage(quint64 requestId, const QByteArray &result) +void QWebEnginePagePrivate::didPrintPage(quint64 requestId, QSharedPointer<QByteArray> result) { #if QT_CONFIG(webengine_printing_and_pdf) + Q_Q(QWebEnginePage); + // If no currentPrinter is set that means that were printing to PDF only. if (!currentPrinter) { - m_callbacks.invoke(requestId, result); + if (!result.data()) + return; + m_callbacks.invoke(requestId, *(result.data())); return; } - bool printerResult = printPdfDataOnPrinter(result, *currentPrinter); + QThread *printerThread = new QThread; + QObject::connect(printerThread, &QThread::finished, printerThread, &QThread::deleteLater); + printerThread->start(); + + PrinterWorker *printerWorker = new PrinterWorker(result, currentPrinter); + QObject::connect(printerWorker, &PrinterWorker::resultReady, q, [requestId, this](bool success) { + currentPrinter = nullptr; + m_callbacks.invoke(requestId, success); + }); + + QObject::connect(printerWorker, &PrinterWorker::resultReady, printerThread, &QThread::quit); + QObject::connect(printerThread, &QThread::finished, printerWorker, &PrinterWorker::deleteLater); + + printerWorker->moveToThread(printerThread); + QMetaObject::invokeMethod(printerWorker, "print"); - currentPrinter = nullptr; - m_callbacks.invoke(requestId, printerResult); #else // we should never enter this branch, but just for safe-keeping... Q_UNUSED(result); @@ -551,7 +487,7 @@ void QWebEnginePagePrivate::authenticationRequired(QSharedPointer<Authentication void QWebEnginePagePrivate::releaseProfile() { - qDebug("Release of profile requested but WebEnginePage still not deleted. Expect troubles !"); + qWarning("Release of profile requested but WebEnginePage still not deleted. Expect troubles !"); // this is not the way to go, but might avoid the crash if user code does not make any calls to page. delete q_ptr->d_ptr.take(); } @@ -617,6 +553,12 @@ void QWebEnginePagePrivate::runRegisterProtocolHandlerRequest(QWebEngineRegister Q_EMIT q->registerProtocolHandlerRequested(request); } +void QWebEnginePagePrivate::runUserNotificationPermissionRequest(const QUrl &securityOrigin) +{ + Q_Q(QWebEnginePage); + Q_EMIT q->featurePermissionRequested(securityOrigin, QWebEnginePage::Notifications); +} + QObject *QWebEnginePagePrivate::accessibilityParentObject() { return view; @@ -1900,6 +1842,40 @@ void QWebEnginePagePrivate::printRequested() }); } +/*! + \since 5.13 + + Registers the request interceptor \a interceptor to intercept URL requests. + + The page does not take ownership of the pointer. This interceptor is called + after any interceptors on the profile, and unlike profile interceptors, is run + on the UI thread, making it thread-safer. Only URL requests from this page are + intercepted. + + To unset the request interceptor, set a \c nullptr. + + \sa QWebEngineUrlRequestInfo, QWebEngineProfile::setRequestInterceptor() +*/ + +void QWebEnginePage::setUrlRequestInterceptor(QWebEngineUrlRequestInterceptor *interceptor) +{ + Q_D(QWebEnginePage); + bool hadInterceptorChanged = bool(d->requestInterceptor) != bool(interceptor); + d->requestInterceptor = interceptor; + if (hadInterceptorChanged) { + if (interceptor) + d->profile->d_ptr->profileAdapter()->addPageRequestInterceptor(); + else + d->profile->d_ptr->profileAdapter()->removePageRequestInterceptor(); + } +} + +void QWebEnginePagePrivate::interceptRequest(QWebEngineUrlRequestInfo &info) +{ + if (requestInterceptor) + requestInterceptor->interceptRequest(info); +} + #if QT_CONFIG(menu) QMenu *QWebEnginePage::createStandardContextMenu() { @@ -1958,6 +1934,7 @@ void QWebEnginePage::setFeaturePermission(const QUrl &securityOrigin, QWebEngine d->adapter->grantMouseLockPermission(true); break; case Notifications: + d->adapter->runUserNotificationRequestCallback(securityOrigin, true); break; } } else { // if (policy == PermissionDeniedByUser) @@ -1976,6 +1953,7 @@ void QWebEnginePage::setFeaturePermission(const QUrl &securityOrigin, QWebEngine d->adapter->grantMouseLockPermission(false); break; case Notifications: + d->adapter->runUserNotificationRequestCallback(securityOrigin, false); break; } } @@ -2488,10 +2466,7 @@ void QWebEnginePage::printToPdf(const QWebEngineCallback<const QByteArray&> &res It is the users responsibility to ensure the \a printer remains valid until \a resultCallback has been called. - \note The rendering of the current content into a temporary PDF document is asynchronous and does - not block the main thread. However, the subsequent rendering of PDF into \a printer runs on the - main thread and will therefore block the event loop. Moreover, printing runs on the browser - process, which is by default not sandboxed. + \note Printing runs on the browser process, which is by default not sandboxed. The \a resultCallback must take a boolean as parameter. If printing was successful, this boolean will have the value \c true, otherwise, its value will be \c false. diff --git a/src/webenginewidgets/api/qwebenginepage.h b/src/webenginewidgets/api/qwebenginepage.h index 028f1a441..4956877a9 100644 --- a/src/webenginewidgets/api/qwebenginepage.h +++ b/src/webenginewidgets/api/qwebenginepage.h @@ -71,6 +71,7 @@ class QWebEngineQuotaRequest; class QWebEngineRegisterProtocolHandlerRequest; class QWebEngineScriptCollection; class QWebEngineSettings; +class QWebEngineUrlRequestInterceptor; class QWEBENGINEWIDGETS_EXPORT QWebEnginePage : public QObject { Q_OBJECT @@ -184,9 +185,7 @@ public: Q_ENUM(NavigationType) enum Feature { -#ifndef Q_QDOC Notifications = 0, -#endif Geolocation = 1, MediaAudioCapture = 2, MediaVideoCapture, @@ -303,6 +302,8 @@ public: void setDevToolsPage(QWebEnginePage *page); QWebEnginePage *devToolsPage() const; + void setUrlRequestInterceptor(QWebEngineUrlRequestInterceptor *interceptor); + const QWebEngineContextMenuData &contextMenuData() const; Q_SIGNALS: diff --git a/src/webenginewidgets/api/qwebenginepage_p.h b/src/webenginewidgets/api/qwebenginepage_p.h index f8f67d341..dc0ead534 100644 --- a/src/webenginewidgets/api/qwebenginepage_p.h +++ b/src/webenginewidgets/api/qwebenginepage_p.h @@ -66,6 +66,8 @@ namespace QtWebEngineCore { class RenderWidgetHostViewQtDelegate; class RenderWidgetHostViewQtDelegateWidget; +class TouchHandleDrawableClient; +class TouchSelectionMenuController; class WebContentsAdapter; } @@ -98,7 +100,6 @@ public: void selectionChanged() override; void recentlyAudibleChanged(bool recentlyAudible) override; QRectF viewportRect() const override; - qreal dpiScale() const override; QColor backgroundColor() const override; void loadStarted(const QUrl &provisionalUrl, bool isErrorPage = false) override; void loadCommitted() override { } @@ -124,7 +125,7 @@ public: void didFetchDocumentMarkup(quint64 requestId, const QString& result) override; void didFetchDocumentInnerText(quint64 requestId, const QString& result) override; void didFindText(quint64 requestId, int matchCount) override; - void didPrintPage(quint64 requestId, const QByteArray &result) override; + void didPrintPage(quint64 requestId, QSharedPointer<QByteArray> result) 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; @@ -132,6 +133,7 @@ public: void releaseProfile() override; void runMediaAccessPermissionRequest(const QUrl &securityOrigin, MediaRequestFlags requestFlags) override; void runGeolocationPermissionRequest(const QUrl &securityOrigin) override; + void runUserNotificationPermissionRequest(const QUrl &securityOrigin) override; void runMouseLockPermissionRequest(const QUrl &securityOrigin) override; void runQuotaRequest(QWebEngineQuotaRequest) override; void runRegisterProtocolHandlerRequest(QWebEngineRegisterProtocolHandlerRequest) override; @@ -151,8 +153,12 @@ public: bool isEnabled() const override; void setToolTip(const QString &toolTipText) override; void printRequested() override; + QtWebEngineCore::TouchHandleDrawableClient *createTouchHandle(const QMap<int, QImage> &) override { return nullptr; } + void showTouchSelectionMenu(QtWebEngineCore::TouchSelectionMenuController *, const QRect &, const QSize &) override { } + void hideTouchSelectionMenu() override { } const QObject *holdingQObject() const override; ClientType clientType() override { return QtWebEngineCore::WebContentsAdapterClient::WidgetsClient; } + void interceptRequest(QWebEngineUrlRequestInfo &) override; void widgetChanged(QtWebEngineCore::RenderWidgetHostViewQtDelegate *newWidget) override; QtWebEngineCore::ProfileAdapter *profileAdapter() override; @@ -195,6 +201,7 @@ public: bool defaultAudioMuted; qreal defaultZoomFactor; QTimer wasShownTimer; + QWebEngineUrlRequestInterceptor *requestInterceptor; QtWebEngineCore::RenderWidgetHostViewQtDelegateWidget *widget = nullptr; mutable QtWebEngineCore::CallbackDirectory m_callbacks; diff --git a/src/webenginewidgets/api/qwebengineprofile.cpp b/src/webenginewidgets/api/qwebengineprofile.cpp index 6644af3ff..f9fcc6136 100644 --- a/src/webenginewidgets/api/qwebengineprofile.cpp +++ b/src/webenginewidgets/api/qwebengineprofile.cpp @@ -43,6 +43,7 @@ #include "qwebenginecookiestore.h" #include "qwebenginedownloaditem.h" #include "qwebenginedownloaditem_p.h" +#include "qwebenginenotificationpresenter_p.h" #include "qwebenginepage.h" #include "qwebenginepage_p.h" #include "qwebenginesettings.h" @@ -140,6 +141,14 @@ using QtWebEngineCore::ProfileAdapter; Both session and persistent cookies are saved to and restored from disk. */ +void QWebEngineProfilePrivate::showNotification(QSharedPointer<QtWebEngineCore::UserNotificationController> &controller) +{ + if (m_notificationPresenter) { + std::unique_ptr<QWebEngineNotification> notification(new QWebEngineNotification(controller)); + m_notificationPresenter(std::move(notification)); + } +} + /*! \fn QWebEngineProfile::downloadRequested(QWebEngineDownloadItem *download) @@ -379,6 +388,36 @@ void QWebEngineProfile::setPersistentStoragePath(const QString &path) } /*! + \since 5.13 + + The path to the location where the downloaded files are stored. + + \note By default, the download path is QStandardPaths::DownloadLocation. + + \sa setDownloadPath(), QStandardPaths::writableLocation() +*/ +QString QWebEngineProfile::downloadPath() const +{ + const Q_D(QWebEngineProfile); + return d->profileAdapter()->downloadPath(); +} + +/*! + \since 5.13 + + Overrides the default path used for download location, setting it to \a path. + + If set to the null string, the default path is restored. + + \sa downloadPath() +*/ +void QWebEngineProfile::setDownloadPath(const QString &path) +{ + Q_D(QWebEngineProfile); + d->profileAdapter()->setDownloadPath(path); +} + +/*! Returns the path used for caches. By default, this is below StandardPaths::CacheLocation in a QtWebengine/StorageName specific @@ -542,19 +581,45 @@ QWebEngineCookieStore* QWebEngineProfile::cookieStore() return d->profileAdapter()->cookieStore(); } - +#if QT_DEPRECATED_SINCE(5, 13) /*! Registers a request interceptor singleton \a interceptor to intercept URL requests. The profile does not take ownership of the pointer. + \obsolete + + Interceptors installed with this method will call + QWebEngineUrlRequestInterceptor::interceptRequest on the I/O thread. Therefore + the user has to provide thread-safe interaction with the other user classes. + Use setUrlRequestInterceptor instead. + \since 5.6 \sa QWebEngineUrlRequestInfo -*/ +*/ void QWebEngineProfile::setRequestInterceptor(QWebEngineUrlRequestInterceptor *interceptor) { Q_D(QWebEngineProfile); + if (interceptor) + interceptor->setProperty("deprecated", true); + d->profileAdapter()->setRequestInterceptor(interceptor); + if (interceptor) + qDebug("Use of deprecated not thread-safe setter, use setUrlRequestInterceptor instead."); +} +#endif +/*! + Registers a request interceptor singleton \a interceptor to intercept URL requests. + + The profile does not take ownership of the pointer. + + \since 5.13 + \sa QWebEngineUrlRequestInfo QWebEngineUrlRequestInterceptor +*/ + +void QWebEngineProfile::setUrlRequestInterceptor(QWebEngineUrlRequestInterceptor *interceptor) +{ + Q_D(QWebEngineProfile); d->profileAdapter()->setRequestInterceptor(interceptor); } @@ -603,6 +668,18 @@ QWebEngineScriptCollection *QWebEngineProfile::scripts() const } /*! + Sets the function \a notificationPresenter as responsible for presenting sent notifications. + + \since 5.13 + \sa QWebEngineNotification +*/ +void QWebEngineProfile::setNotificationPresenter(std::function<void(std::unique_ptr<QWebEngineNotification>)> notificationPresenter) +{ + Q_D(QWebEngineProfile); + d->m_notificationPresenter = std::move(notificationPresenter); +} + +/*! Returns the default profile. The default profile uses the storage name "Default". @@ -614,6 +691,8 @@ QWebEngineProfile *QWebEngineProfile::defaultProfile() static QWebEngineProfile* profile = new QWebEngineProfile( new QWebEngineProfilePrivate(ProfileAdapter::createDefaultProfileAdapter()), ProfileAdapter::globalQObjectRoot()); + if (!profile->d_ptr->m_notificationPresenter) + profile->setNotificationPresenter(&defaultNotificationPresenter); return profile; } @@ -689,7 +768,7 @@ QWebEngineSettings *QWebEngineProfile::settings() const const QWebEngineUrlSchemeHandler *QWebEngineProfile::urlSchemeHandler(const QByteArray &scheme) const { const Q_D(QWebEngineProfile); - return d->profileAdapter()->customUrlSchemeHandlers().value(scheme.toLower()); + return d->profileAdapter()->urlSchemeHandler(scheme); } /*! @@ -703,10 +782,7 @@ const QWebEngineUrlSchemeHandler *QWebEngineProfile::urlSchemeHandler(const QByt void QWebEngineProfile::installUrlSchemeHandler(const QByteArray &scheme, QWebEngineUrlSchemeHandler *handler) { Q_D(QWebEngineProfile); - Q_ASSERT(handler); - if (!d->profileAdapter()->addCustomUrlSchemeHandler(scheme, handler)) - return; - connect(handler, SIGNAL(_q_destroyedUrlSchemeHandler(QWebEngineUrlSchemeHandler*)), this, SLOT(destroyedUrlSchemeHandler(QWebEngineUrlSchemeHandler*))); + d->profileAdapter()->installUrlSchemeHandler(scheme, handler); } /*! @@ -719,10 +795,7 @@ void QWebEngineProfile::installUrlSchemeHandler(const QByteArray &scheme, QWebEn void QWebEngineProfile::removeUrlSchemeHandler(QWebEngineUrlSchemeHandler *handler) { Q_D(QWebEngineProfile); - Q_ASSERT(handler); - if (!d->profileAdapter()->removeCustomUrlSchemeHandler(handler)) - return; - disconnect(handler, SIGNAL(_q_destroyedUrlSchemeHandler(QWebEngineUrlSchemeHandler*)), this, SLOT(destroyedUrlSchemeHandler(QWebEngineUrlSchemeHandler*))); + d->profileAdapter()->removeUrlSchemeHandler(handler); } /*! @@ -735,10 +808,7 @@ void QWebEngineProfile::removeUrlSchemeHandler(QWebEngineUrlSchemeHandler *handl void QWebEngineProfile::removeUrlScheme(const QByteArray &scheme) { Q_D(QWebEngineProfile); - QWebEngineUrlSchemeHandler *handler = d->profileAdapter()->takeCustomUrlSchemeHandler(scheme); - if (!handler) - return; - disconnect(handler, SIGNAL(_q_destroyedUrlSchemeHandler(QWebEngineUrlSchemeHandler*)), this, SLOT(destroyedUrlSchemeHandler(QWebEngineUrlSchemeHandler*))); + d->profileAdapter()->removeUrlScheme(scheme); } /*! @@ -749,12 +819,43 @@ void QWebEngineProfile::removeUrlScheme(const QByteArray &scheme) void QWebEngineProfile::removeAllUrlSchemeHandlers() { Q_D(QWebEngineProfile); - d->profileAdapter()->clearCustomUrlSchemeHandlers(); + d->profileAdapter()->removeAllUrlSchemeHandlers(); } -void QWebEngineProfile::destroyedUrlSchemeHandler(QWebEngineUrlSchemeHandler *obj) +/*! + \since 5.13 + + Sets if this profile is to be used for downloading and caching when needed + during certificate verification, for instance for OCSP, CRLs, and AIA. + + Only one QWebEngineProfile can do this at a time, and it is recommended + that the profile fullfilling this role has a disk HTTP cache to avoid + needlessly re-downloading. If you set the option on a second profile, + it will be disabled on the profile it is currently set. + + Currently only affects Linux/NSS installations where it enables OCSP. + + As long as one profile has \a enabled set to \c true, all other profiles + will be able to use it for their certificate verification. + + \sa isUsedForGlobalCertificateVerification(), httpCacheType() +*/ +void QWebEngineProfile::setUseForGlobalCertificateVerification(bool enabled) { - removeUrlSchemeHandler(obj); + Q_D(QWebEngineProfile); + d->profileAdapter()->setUseForGlobalCertificateVerification(enabled); +} + +/*! + \since 5.13 + + Returns \c true if this profile is currently being used for global + certificate verification. +*/ +bool QWebEngineProfile::isUsedForGlobalCertificateVerification() const +{ + Q_D(const QWebEngineProfile); + return d->profileAdapter()->isUsedForGlobalCertificateVerification(); } /*! @@ -768,4 +869,19 @@ void QWebEngineProfile::clearHttpCache() d->profileAdapter()->clearHttpCache(); } +/*! + \since 5.13 + + Returns the profile's client certificate store. +*/ +QWebEngineClientCertificateStore *QWebEngineProfile::clientCertificateStore() +{ +#if QT_CONFIG(ssl) + Q_D(QWebEngineProfile); + return d->profileAdapter()->clientCertificateStore(); +#else + return nullptr; +#endif +} + QT_END_NAMESPACE diff --git a/src/webenginewidgets/api/qwebengineprofile.h b/src/webenginewidgets/api/qwebengineprofile.h index f9a564cd2..794ba6279 100644 --- a/src/webenginewidgets/api/qwebengineprofile.h +++ b/src/webenginewidgets/api/qwebengineprofile.h @@ -46,12 +46,17 @@ #include <QtCore/qscopedpointer.h> #include <QtCore/qstring.h> +#include <functional> +#include <memory> + QT_BEGIN_NAMESPACE class QObject; class QUrl; +class QWebEngineClientCertificateStore; class QWebEngineCookieStore; class QWebEngineDownloadItem; +class QWebEngineNotification; class QWebEnginePage; class QWebEnginePagePrivate; class QWebEngineProfilePrivate; @@ -106,7 +111,10 @@ public: void setHttpCacheMaximumSize(int maxSize); QWebEngineCookieStore* cookieStore(); +#if QT_DEPRECATED_SINCE(5, 13) void setRequestInterceptor(QWebEngineUrlRequestInterceptor *interceptor); +#endif + void setUrlRequestInterceptor(QWebEngineUrlRequestInterceptor *interceptor); void clearAllVisitedLinks(); void clearVisitedLinks(const QList<QUrl> &urls); @@ -128,19 +136,27 @@ public: void setSpellCheckEnabled(bool enabled); bool isSpellCheckEnabled() const; + void setUseForGlobalCertificateVerification(bool enabled = true); + bool isUsedForGlobalCertificateVerification() const; + + QString downloadPath() const; + void setDownloadPath(const QString &path); + + void setNotificationPresenter(std::function<void(std::unique_ptr<QWebEngineNotification>)> notificationPresenter); + + QWebEngineClientCertificateStore *clientCertificateStore(); + static QWebEngineProfile *defaultProfile(); Q_SIGNALS: void downloadRequested(QWebEngineDownloadItem *download); -private Q_SLOTS: - void destroyedUrlSchemeHandler(QWebEngineUrlSchemeHandler *obj); - private: Q_DISABLE_COPY(QWebEngineProfile) Q_DECLARE_PRIVATE(QWebEngineProfile) QWebEngineProfile(QWebEngineProfilePrivate *, QObject *parent = Q_NULLPTR); + friend class QWebEnginePage; friend class QWebEnginePagePrivate; friend class QWebEngineUrlSchemeHandler; QScopedPointer<QWebEngineProfilePrivate> d_ptr; diff --git a/src/webenginewidgets/api/qwebengineprofile_p.h b/src/webenginewidgets/api/qwebengineprofile_p.h index cb43dace5..64e9500b0 100644 --- a/src/webenginewidgets/api/qwebengineprofile_p.h +++ b/src/webenginewidgets/api/qwebengineprofile_p.h @@ -60,6 +60,8 @@ #include <QScopedPointer> #include <QSharedPointer> +#include <functional> + namespace QtWebEngineCore { class ProfileAdapter; } @@ -68,6 +70,7 @@ QT_BEGIN_NAMESPACE class QWebEngineBrowserContext; class QWebEngineProfilePrivate; +class QWebEngineNotification; class QWebEngineSettings; class QWebEngineProfilePrivate : public QtWebEngineCore::ProfileAdapterClient { @@ -86,6 +89,8 @@ public: void downloadRequested(DownloadItemInfo &info) override; void downloadUpdated(const DownloadItemInfo &info) override; + void showNotification(QSharedPointer<QtWebEngineCore::UserNotificationController> &) override; + void addWebContentsAdapterClient(QtWebEngineCore::WebContentsAdapterClient *adapter) override; void removeWebContentsAdapterClient(QtWebEngineCore::WebContentsAdapterClient *adapter) override; @@ -95,6 +100,7 @@ private: QPointer<QtWebEngineCore::ProfileAdapter> m_profileAdapter; QScopedPointer<QWebEngineScriptCollection> m_scriptCollection; QMap<quint32, QPointer<QWebEngineDownloadItem> > m_ongoingDownloads; + std::function<void(std::unique_ptr<QWebEngineNotification>)> m_notificationPresenter; }; QT_END_NAMESPACE diff --git a/src/webenginewidgets/api/qwebenginesettings.cpp b/src/webenginewidgets/api/qwebenginesettings.cpp index d91eb3f97..d9fb3b000 100644 --- a/src/webenginewidgets/api/qwebenginesettings.cpp +++ b/src/webenginewidgets/api/qwebenginesettings.cpp @@ -109,7 +109,8 @@ static WebEngineSettings::Attribute toWebEngineAttribute(QWebEngineSettings::Web return WebEngineSettings::JavascriptCanPaste; case QWebEngineSettings::DnsPrefetchEnabled: return WebEngineSettings::DnsPrefetchEnabled; - + case QWebEngineSettings::PdfViewerEnabled: + return WebEngineSettings::PdfViewerEnabled; default: return WebEngineSettings::UnsupportedInCoreSettings; } diff --git a/src/webenginewidgets/api/qwebenginesettings.h b/src/webenginewidgets/api/qwebenginesettings.h index 9100e32d5..d39291fed 100644 --- a/src/webenginewidgets/api/qwebenginesettings.h +++ b/src/webenginewidgets/api/qwebenginesettings.h @@ -96,6 +96,7 @@ public: WebRTCPublicInterfacesOnly, JavascriptCanPaste, DnsPrefetchEnabled, + PdfViewerEnabled, }; enum FontSize { diff --git a/src/webenginewidgets/api/qwebengineview.cpp b/src/webenginewidgets/api/qwebengineview.cpp index 381f1385c..6e1138522 100644 --- a/src/webenginewidgets/api/qwebengineview.cpp +++ b/src/webenginewidgets/api/qwebengineview.cpp @@ -61,6 +61,7 @@ void QWebEngineViewPrivate::pageChanged(QWebEnginePage *oldPage, QWebEnginePage Q_Q(QWebEngineView); if (oldPage) { + oldPage->d_ptr->wasHidden(); oldPage->disconnect(q); } @@ -74,6 +75,8 @@ void QWebEngineViewPrivate::pageChanged(QWebEnginePage *oldPage, QWebEnginePage QObject::connect(newPage, &QWebEnginePage::loadFinished, q, &QWebEngineView::loadFinished); QObject::connect(newPage, &QWebEnginePage::selectionChanged, q, &QWebEngineView::selectionChanged); QObject::connect(newPage, &QWebEnginePage::renderProcessTerminated, q, &QWebEngineView::renderProcessTerminated); + if (q->isVisible()) + newPage->d_ptr->wasShown(); } auto oldUrl = oldPage ? oldPage->url() : QUrl(); @@ -119,7 +122,7 @@ static QAccessibleInterface *webAccessibleFactory(const QString &, QObject *obje { if (QWebEngineView *v = qobject_cast<QWebEngineView*>(object)) return new QWebEngineViewAccessible(v); - return Q_NULLPTR; + return nullptr; } #endif // QT_NO_ACCESSIBILITY @@ -461,7 +464,7 @@ QAccessibleInterface *QWebEngineViewAccessible::child(int index) const { if (index == 0 && view() && view()->page()) return view()->page()->d_func()->adapter->browserAccessible(); - return Q_NULLPTR; + return nullptr; } int QWebEngineViewAccessible::indexOfChild(const QAccessibleInterface *c) const diff --git a/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc b/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc index 2bf4d0413..e5c0c0c3e 100644 --- a/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc +++ b/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc @@ -287,6 +287,8 @@ This enum describes the platform feature access categories that the user may be asked to grant or deny access to: + \value Notifications + Web notifications for the end-user. \value Geolocation Location hardware or service. \value MediaAudioCapture diff --git a/src/webenginewidgets/doc/src/qwebenginesettings_lgpl.qdoc b/src/webenginewidgets/doc/src/qwebenginesettings_lgpl.qdoc index 88f6e05c2..ce75a4203 100644 --- a/src/webenginewidgets/doc/src/qwebenginesettings_lgpl.qdoc +++ b/src/webenginewidgets/doc/src/qwebenginesettings_lgpl.qdoc @@ -188,7 +188,9 @@ \value DnsPrefetchEnabled Specifies whether WebEngine will try to pre-fetch DNS entries to speed up browsing. Disabled by default. (Added in Qt 5.12) - + \value PdfViewerEnabled Specifies that PDF documents will be opened in the internal PDF viewer + instead of being downloaded. + Enabled by default. (Added in Qt 5.13) */ /*! diff --git a/src/webenginewidgets/printer_worker.cpp b/src/webenginewidgets/printer_worker.cpp new file mode 100644 index 000000000..94a862cda --- /dev/null +++ b/src/webenginewidgets/printer_worker.cpp @@ -0,0 +1,169 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "printer_worker.h" + +#include "printing/pdfium_document_wrapper_qt.h" + +#include <QPainter> +#include <QPrinter> + +namespace QtWebEngineCore { + +PrinterWorker::PrinterWorker(QSharedPointer<QByteArray> data, QPrinter *printer) + : m_data(data) + , m_printer(printer) +{ +} + +PrinterWorker::~PrinterWorker() +{ +} + +void PrinterWorker::print() +{ + if (!m_data->size()) { + qWarning("Failure to print on printer %ls: Print result data is empty.", + qUtf16Printable(m_printer->printerName())); + Q_EMIT resultReady(false); + return; + } + + PdfiumDocumentWrapperQt pdfiumWrapper(m_data->constData(), m_data->size()); + + int toPage = m_printer->toPage(); + int fromPage = m_printer->fromPage(); + bool ascendingOrder = true; + + if (fromPage == 0 && toPage == 0) { + fromPage = 1; + toPage = pdfiumWrapper.pageCount(); + } + fromPage = qMax(1, fromPage); + toPage = qMin(pdfiumWrapper.pageCount(), toPage); + + if (m_printer->pageOrder() == QPrinter::LastPageFirst) { + qSwap(fromPage, toPage); + ascendingOrder = false; + } + + int pageCopies = 1; + int documentCopies = 1; + + if (!m_printer->supportsMultipleCopies()) + documentCopies = m_printer->copyCount(); + + if (m_printer->collateCopies()) { + pageCopies = documentCopies; + documentCopies = 1; + } + + bool isLandscape = pdfiumWrapper.pageIsLandscape(0); + QPageLayout::Orientation prevOrientation = m_printer->pageLayout().orientation(); + m_printer->setPageOrientation(isLandscape ? QPageLayout::Landscape : QPageLayout::Portrait); + + QPainter painter; + if (!painter.begin(m_printer)) { + qWarning("Failure to print on printer %ls: Could not open printer for painting.", + qUtf16Printable(m_printer->printerName())); + Q_EMIT resultReady(false); + return; + } + + for (int printedDocuments = 0; printedDocuments < documentCopies; printedDocuments++) { + if (printedDocuments > 0) + m_printer->newPage(); + + int currentPageIndex = fromPage; + + for (int i = 0; true; i++) { + prevOrientation = m_printer->pageLayout().orientation(); + isLandscape = pdfiumWrapper.pageIsLandscape(currentPageIndex - 1); + m_printer->setPageOrientation(isLandscape ? QPageLayout::Landscape : QPageLayout::Portrait); + + QSize pageSize = m_printer->pageRect().size(); + + if (i > 0) + m_printer->newPage(); + + for (int printedPages = 0; printedPages < pageCopies; printedPages++) { + if (m_printer->printerState() == QPrinter::Aborted + || m_printer->printerState() == QPrinter::Error) { + Q_EMIT resultReady(false); + return; + } + + if (printedPages > 0) + m_printer->newPage(); + + QImage currentImage = pdfiumWrapper.pageAsQImage(currentPageIndex - 1); + if (currentImage.isNull()) { + Q_EMIT resultReady(false); + return; + } + + QRect targetRect = currentImage.rect(); + // Scale down currentImage by both width and height to fit into the drawable area of the page. + float scaleFactor = (float)pageSize.width() / (float)targetRect.width(); + targetRect = QRect(0, 0, targetRect.width() * scaleFactor, targetRect.height() * scaleFactor); + scaleFactor = (float)pageSize.height() / (float)targetRect.height(); + targetRect = QRect(0, 0, targetRect.width() * scaleFactor, targetRect.height() * scaleFactor); + + // Painting operations are automatically clipped to the bounds of the drawable part of the page. + painter.drawImage(targetRect, currentImage, currentImage.rect()); + } + + if (currentPageIndex == toPage) + break; + + if (ascendingOrder) + currentPageIndex++; + else + currentPageIndex--; + + m_printer->setPageOrientation(prevOrientation); + } + } + painter.end(); + + Q_EMIT resultReady(true); + return; +} + +} // namespace QtWebEngineCore diff --git a/src/webenginewidgets/printer_worker.h b/src/webenginewidgets/printer_worker.h new file mode 100644 index 000000000..96025c90e --- /dev/null +++ b/src/webenginewidgets/printer_worker.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// 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. +// + +#ifndef PRINTER_WORKER_H +#define PRINTER_WORKER_H + +#include "qtwebenginecoreglobal_p.h" + +#include <QSharedPointer> + +QT_BEGIN_NAMESPACE +class QPrinter; +QT_END_NAMESPACE + +namespace QtWebEngineCore { + +class PrinterWorker : public QObject +{ + Q_OBJECT +public: + PrinterWorker(QSharedPointer<QByteArray> data, QPrinter *printer); + virtual ~PrinterWorker(); + +public Q_SLOTS: + void print(); + +Q_SIGNALS: + void resultReady(bool success); + +private: + Q_DISABLE_COPY(PrinterWorker) + + QSharedPointer<QByteArray> m_data; + QPrinter *m_printer; +}; + +} // namespace QtWebEngineCore + +Q_DECLARE_METATYPE(QtWebEngineCore::PrinterWorker*) + +#endif // PRINTER_WORKER_H diff --git a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp index 18f1e97d0..88eb9843b 100644 --- a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp +++ b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp @@ -124,25 +124,31 @@ RenderWidgetHostViewQtDelegateWidget::RenderWidgetHostViewQtDelegateWidget(Rende "QSurfaceFormat before the QtGui application instance is created."); } #endif - - // Make sure the OpenGL profile of the QQuickWidget matches the shared context profile. - if (sharedFormat.profile() == QSurfaceFormat::CoreProfile) { - int major; - int minor; - QSurfaceFormat::OpenGLContextProfile profile; - + int major; + int minor; + QSurfaceFormat::OpenGLContextProfile profile; #ifdef Q_OS_MACOS - // Due to QTBUG-63180, requesting the sharedFormat.majorVersion() on macOS will lead to - // a failed creation of QQuickWidget shared context. Thus make sure to request the - // major version specified in the defaultFormat instead. - major = defaultFormat.majorVersion(); - minor = defaultFormat.minorVersion(); - profile = defaultFormat.profile(); + // Due to QTBUG-63180, requesting the sharedFormat.majorVersion() on macOS will lead to + // a failed creation of QQuickWidget shared context. Thus make sure to request the + // major version specified in the defaultFormat instead. + major = defaultFormat.majorVersion(); + minor = defaultFormat.minorVersion(); + profile = defaultFormat.profile(); #else - major = sharedFormat.majorVersion(); - minor = sharedFormat.minorVersion(); - profile = sharedFormat.profile(); + major = sharedFormat.majorVersion(); + minor = sharedFormat.minorVersion(); + profile = sharedFormat.profile(); #endif + + // Make sure the OpenGL profile of the QQuickWidget matches the shared context profile. + // It covers the following cases: + // 1) Desktop OpenGL Core Profile. + // 2) Windows ANGLE OpenGL ES profile. + if (sharedFormat.profile() == QSurfaceFormat::CoreProfile +#ifdef Q_OS_WIN + || globalSharedContext->isOpenGLES() +#endif + ) { format.setMajorVersion(major); format.setMinorVersion(minor); format.setProfile(profile); @@ -183,7 +189,7 @@ void RenderWidgetHostViewQtDelegateWidget::removeParentBeforeParentDelete() { // Unset the parent, because parent is being destroyed, but the owner of this // RenderWidgetHostViewQtDelegateWidget is actually a RenderWidgetHostViewQt instance. - setParent(Q_NULLPTR); + setParent(nullptr); // If this widget represents a popup window, make sure to close it, so that if the popup was the // last visible top level window, the application event loop can quit if it deems it necessarry. @@ -219,15 +225,16 @@ void RenderWidgetHostViewQtDelegateWidget::closeEvent(QCloseEvent *event) m_client->closePopup(); } -QRectF RenderWidgetHostViewQtDelegateWidget::screenRect() const +QRectF RenderWidgetHostViewQtDelegateWidget::viewGeometry() const { - return QRectF(x(), y(), width(), height()); + return QRectF(mapToGlobal(pos()), size()); } -QRectF RenderWidgetHostViewQtDelegateWidget::contentsRect() const +QRect RenderWidgetHostViewQtDelegateWidget::windowGeometry() const { - QPointF pos = mapToGlobal(QPoint(0, 0)); - return QRectF(pos.x(), pos.y(), width(), height()); + if (!window()) + return QRect(); + return window()->frameGeometry(); } void RenderWidgetHostViewQtDelegateWidget::setKeyboardFocus() @@ -365,14 +372,7 @@ QVariant RenderWidgetHostViewQtDelegateWidget::inputMethodQuery(Qt::InputMethodQ void RenderWidgetHostViewQtDelegateWidget::resizeEvent(QResizeEvent *resizeEvent) { QQuickWidget::resizeEvent(resizeEvent); - - const QPoint globalPos = mapToGlobal(pos()); - if (globalPos != m_lastGlobalPos) { - m_lastGlobalPos = globalPos; - m_client->windowBoundsChanged(); - } - - m_client->notifyResize(); + m_client->visualPropertiesChanged(); } void RenderWidgetHostViewQtDelegateWidget::showEvent(QShowEvent *event) @@ -388,7 +388,7 @@ void RenderWidgetHostViewQtDelegateWidget::showEvent(QShowEvent *event) m_windowConnections.append(connect(w, SIGNAL(xChanged(int)), SLOT(onWindowPosChanged()))); m_windowConnections.append(connect(w, SIGNAL(yChanged(int)), SLOT(onWindowPosChanged()))); } - m_client->windowChanged(); + m_client->visualPropertiesChanged(); m_client->notifyShown(); } @@ -486,8 +486,7 @@ bool RenderWidgetHostViewQtDelegateWidget::event(QEvent *event) void RenderWidgetHostViewQtDelegateWidget::onWindowPosChanged() { - m_lastGlobalPos = mapToGlobal(pos()); - m_client->windowBoundsChanged(); + m_client->visualPropertiesChanged(); } } // namespace QtWebEngineCore diff --git a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h index c1cd90093..7746c4405 100644 --- a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h +++ b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h @@ -66,8 +66,8 @@ public: ~RenderWidgetHostViewQtDelegateWidget(); void initAsPopup(const QRect&) override; - QRectF screenRect() const override; - QRectF contentsRect() const override; + QRectF viewGeometry() const override; + QRect windowGeometry() const override; void setKeyboardFocus() override; bool hasKeyboardFocus() override; void lockMouse() override; @@ -111,7 +111,6 @@ private: QScopedPointer<QQuickItem> m_rootItem; bool m_isPopup; QColor m_clearColor; - QPoint m_lastGlobalPos; QList<QMetaObject::Connection> m_windowConnections; QWebEnginePage *m_page = nullptr; QMetaObject::Connection m_parentDestroyedConnection; diff --git a/src/webenginewidgets/webenginewidgets.pro b/src/webenginewidgets/webenginewidgets.pro index e61575d3a..d4fb40dc7 100644 --- a/src/webenginewidgets/webenginewidgets.pro +++ b/src/webenginewidgets/webenginewidgets.pro @@ -19,6 +19,7 @@ SOURCES = \ api/qwebenginedownloaditem.cpp \ api/qwebenginefullscreenrequest.cpp \ api/qwebenginehistory.cpp \ + api/qwebenginenotificationpresenter.cpp \ api/qwebenginepage.cpp \ api/qwebengineprofile.cpp \ api/qwebenginescript.cpp \ @@ -36,6 +37,7 @@ HEADERS = \ api/qwebenginedownloaditem_p.h \ api/qwebenginefullscreenrequest.h \ api/qwebenginehistory.h \ + api/qwebenginenotificationpresenter_p.h \ api/qwebenginepage.h \ api/qwebenginepage_p.h \ api/qwebengineprofile.h \ @@ -49,6 +51,9 @@ HEADERS = \ qtConfig(webengine-printing-and-pdf) { QT += printsupport + + SOURCES += printer_worker.cpp + HEADERS += printer_worker.h } load(qt_module) |