diff options
Diffstat (limited to 'src/core')
101 files changed, 6228 insertions, 3194 deletions
diff --git a/src/core/api/core_api.pro b/src/core/api/core_api.pro index d53fb6942..68a14514f 100644 --- a/src/core/api/core_api.pro +++ b/src/core/api/core_api.pro @@ -36,9 +36,11 @@ HEADERS = \ qwebengineclientcertificatestore.h \ qtwebenginecoreglobal.h \ qtwebenginecoreglobal_p.h \ + qwebenginecertificateerror.h \ qwebenginecookiestore.h \ qwebenginecookiestore_p.h \ qwebenginefindtextresult.h \ + qwebenginefullscreenrequest.h \ qwebenginehttprequest.h \ qwebenginemessagepumpscheduler_p.h \ qwebenginenotification.h \ @@ -49,13 +51,23 @@ HEADERS = \ qwebengineurlrequestinfo_p.h \ qwebengineurlrequestjob.h \ qwebengineurlscheme.h \ - qwebengineurlschemehandler.h + qwebengineurlschemehandler.h \ + qwebenginecontextmenurequest.h \ + qwebenginecontextmenurequest_p.h \ + qwebenginedownloadrequest.h \ + qwebenginedownloadrequest_p.h \ + qwebenginesettings.h \ + qwebenginescript.h \ + qwebenginescriptcollection.h \ + qwebenginescriptcollection_p.h SOURCES = \ qtwebenginecoreglobal.cpp \ + qwebenginecertificateerror.cpp \ qwebengineclientcertificatestore.cpp \ qwebenginecookiestore.cpp \ qwebenginefindtextresult.cpp \ + qwebenginefullscreenrequest.cpp \ qwebenginehttprequest.cpp \ qwebenginemessagepumpscheduler.cpp \ qwebenginenotification.cpp \ @@ -64,13 +76,12 @@ SOURCES = \ qwebengineurlrequestinfo.cpp \ qwebengineurlrequestjob.cpp \ qwebengineurlscheme.cpp \ - qwebengineurlschemehandler.cpp - -### Qt6 Remove this workaround -unix:!isEmpty(QMAKE_LFLAGS_VERSION_SCRIPT):!static { - SOURCES += qtbug-60565.cpp \ - qtbug-61521.cpp -} + qwebengineurlschemehandler.cpp \ + qwebenginecontextmenurequest.cpp \ + qwebenginedownloadrequest.cpp \ + qwebenginesettings.cpp \ + qwebenginescript.cpp \ + qwebenginescriptcollection.cpp # Chromium headers included are not remotely clean CONFIG -= warning_clean diff --git a/src/core/api/qtbug-60565.cpp b/src/core/api/qtbug-60565.cpp deleted file mode 100644 index f48a2a701..000000000 --- a/src/core/api/qtbug-60565.cpp +++ /dev/null @@ -1,138 +0,0 @@ -/**************************************************************************** -** -** 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 <new> -#include <unistd.h> - -#if defined(__LP64__) -# define SIZE_T_MANGLING "m" -#else -# define SIZE_T_MANGLING "j" -#endif - -#define SHIM_ALIAS_SYMBOL(fn) __attribute__((weak, alias(#fn))) -#define SHIM_HIDDEN __attribute__ ((visibility ("hidden"))) - -extern "C" { - -__asm__(".symver __ShimCppNew, _Znw" SIZE_T_MANGLING "@Qt_5"); -void* __ShimCppNew(size_t size) - SHIM_ALIAS_SYMBOL(ShimCppNew); - -__asm__(".symver __ShimCppDelete, _ZdlPv@Qt_5"); -void __ShimCppDelete(void* address) - SHIM_ALIAS_SYMBOL(ShimCppDelete); - -__asm__(".symver __ShimCppNewArray, _Zna" SIZE_T_MANGLING "@Qt_5"); -void* __ShimCppNewArray(size_t size) - SHIM_ALIAS_SYMBOL(ShimCppNewArray); - -__asm__(".symver __ShimCppDeleteArray, _ZdaPv@Qt_5"); -void __ShimCppDeleteArray(void* address) - SHIM_ALIAS_SYMBOL(ShimCppDeleteArray); - -__asm__(".symver __ShimCppNewNoThrow, _Znw" SIZE_T_MANGLING "RKSt9nothrow_t@Qt_5"); -void *__ShimCppNewNoThrow(size_t size, const std::nothrow_t&) noexcept - SHIM_ALIAS_SYMBOL(ShimCppNewNoThrow); - -__asm__(".symver __ShimCppNewArrayNoThrow, _Zna" SIZE_T_MANGLING "RKSt9nothrow_t@Qt_5"); -void *__ShimCppNewArrayNoThrow(size_t size, const std::nothrow_t&) noexcept - SHIM_ALIAS_SYMBOL(ShimCppNewArrayNoThrow); - -__asm__(".symver __ShimCppDeleteNoThrow, _ZdlPvRKSt9nothrow_t@Qt_5"); -void __ShimCppDeleteNoThrow(void* address, const std::nothrow_t&) noexcept - SHIM_ALIAS_SYMBOL(ShimCppDeleteNoThrow); - -__asm__(".symver __ShimCppDeleteArrayNoThrow, _ZdaPvRKSt9nothrow_t@Qt_5"); -void __ShimCppDeleteArrayNoThrow(void* address, const std::nothrow_t&) noexcept - SHIM_ALIAS_SYMBOL(ShimCppDeleteArrayNoThrow); - -static void* __shimCppNew(size_t size); -static void* __shimCppNewArray(size_t size); -static void __shimCppDelete(void *address); -static void __shimCppDeleteArray(void *address); - -SHIM_HIDDEN void* ShimCppNew(size_t size) { - return __shimCppNew(size); -} - -SHIM_HIDDEN void* ShimCppNewNoThrow(size_t size, const std::nothrow_t&) noexcept { - return __shimCppNew(size); -} - -SHIM_HIDDEN void* ShimCppNewArray(size_t size) { - return __shimCppNewArray(size); -} - -SHIM_HIDDEN void* ShimCppNewArrayNoThrow(size_t size, const std::nothrow_t&) noexcept { - return __shimCppNewArray(size); -} - -SHIM_HIDDEN void ShimCppDelete(void* address) { - __shimCppDelete(address); -} - -SHIM_HIDDEN void ShimCppDeleteNoThrow(void* address, const std::nothrow_t&) noexcept { - __shimCppDelete(address); -} - -SHIM_HIDDEN void ShimCppDeleteArray(void* address) { - __shimCppDeleteArray(address); -} - -SHIM_HIDDEN void ShimCppDeleteArrayNoThrow(void* address, const std::nothrow_t&) noexcept { - __shimCppDeleteArray(address); -} -} // extern "C" - -static void* __shimCppNew(size_t size) { - return operator new(size); -} - -static void* __shimCppNewArray(size_t size) { - return operator new[](size); -} - -static void __shimCppDelete(void* address) { - operator delete(address); -} - -static void __shimCppDeleteArray(void* address) { - operator delete[](address); -} diff --git a/src/core/api/qtbug-61521.cpp b/src/core/api/qtbug-61521.cpp deleted file mode 100644 index 002a1af22..000000000 --- a/src/core/api/qtbug-61521.cpp +++ /dev/null @@ -1,120 +0,0 @@ -/**************************************************************************** -** -** 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 <stdlib.h> -#include <malloc.h> - -#define SHIM_ALIAS_SYMBOL(fn) __attribute__((weak, alias(#fn))) -#define SHIM_SYMBOL_VERSION(fn) __asm__(".symver __" #fn "," #fn "@Qt_5") -#define SHIM_HIDDEN __attribute__ ((visibility ("hidden"))) - -extern "C" { - -SHIM_SYMBOL_VERSION(malloc); -void* __malloc(size_t size) - SHIM_ALIAS_SYMBOL(ShimMalloc); - -SHIM_SYMBOL_VERSION(free); -void __free(void* ptr) - SHIM_ALIAS_SYMBOL(ShimFree); - -SHIM_SYMBOL_VERSION(realloc); -void* __realloc(void* ptr, size_t size) - SHIM_ALIAS_SYMBOL(ShimRealloc); - -SHIM_SYMBOL_VERSION(calloc); -void* __calloc(size_t n, size_t size) - SHIM_ALIAS_SYMBOL(ShimCalloc); - -SHIM_SYMBOL_VERSION(cfree); -void __cfree(void* ptr) - SHIM_ALIAS_SYMBOL(ShimCFree); - -SHIM_SYMBOL_VERSION(memalign); -void* __memalign(size_t align, size_t s) - SHIM_ALIAS_SYMBOL(ShimMemalign); - -SHIM_SYMBOL_VERSION(valloc); -void* __valloc(size_t size) - SHIM_ALIAS_SYMBOL(ShimValloc); - -SHIM_SYMBOL_VERSION(pvalloc); -void* __pvalloc(size_t size) - SHIM_ALIAS_SYMBOL(ShimPvalloc); - -SHIM_SYMBOL_VERSION(posix_memalign); -int __posix_memalign(void** r, size_t a, size_t s) - SHIM_ALIAS_SYMBOL(ShimPosixMemalign); - -SHIM_HIDDEN void* ShimMalloc(size_t size) { - return malloc(size); -} - -SHIM_HIDDEN void ShimFree(void* ptr) { - free(ptr); -} - -SHIM_HIDDEN void* ShimRealloc(void* ptr, size_t size) { - return realloc(ptr,size); -} - -SHIM_HIDDEN void* ShimCalloc(size_t n, size_t size) { - return calloc(n,size); -} - -SHIM_HIDDEN void ShimCFree(void* ptr) { - free(ptr); -} - -SHIM_HIDDEN void* ShimMemalign(size_t align, size_t s) { - return memalign(align,s); -} - -SHIM_HIDDEN void* ShimValloc(size_t size) { - return valloc(size); -} - -SHIM_HIDDEN void* ShimPvalloc(size_t size) { - return pvalloc(size); -} - -SHIM_HIDDEN int ShimPosixMemalign(void** r, size_t a, size_t s) { - return posix_memalign(r,a,s); -} -} // extern "C" diff --git a/src/core/api/qtwebenginecoreglobal.cpp b/src/core/api/qtwebenginecoreglobal.cpp index 3c9387a10..0e0c4b63b 100644 --- a/src/core/api/qtwebenginecoreglobal.cpp +++ b/src/core/api/qtwebenginecoreglobal.cpp @@ -105,83 +105,104 @@ Q_WEBENGINECORE_PRIVATE_EXPORT void initialize() qputenv("QT_MAC_PRO_WEBENGINE_WORKAROUND", "1"); #endif // No need to override the shared context if QApplication already set one (e.g with Qt::AA_ShareOpenGLContexts). - if (qt_gl_global_share_context()) - return; + if (!qt_gl_global_share_context()) { - QCoreApplication *app = QCoreApplication::instance(); - if (!app) { - qFatal("QtWebEngine::initialize() but no core application instance."); - return; - } - - // Bail out silently if the user did not construct a QGuiApplication. - if (!qobject_cast<QGuiApplication *>(app)) - return; - - if (app->thread() != QThread::currentThread()) { - qFatal("QtWebEngine::initialize() must be called from the Qt gui thread."); - return; - } + QCoreApplication *app = QCoreApplication::instance(); + if (!app) { + qFatal("QtWebEngine::initialize() but no core application instance."); + return; + } - if (shareContext) - return; + // Bail out silently if the user did not construct a QGuiApplication. + if (!qobject_cast<QGuiApplication *>(app)) + return; - shareContext = new QOpenGLContext; - QSurfaceFormat format = QSurfaceFormat::defaultFormat(); -// format.setOption(QSurfaceFormat::ResetNotification); + if (app->thread() != QThread::currentThread()) { + qFatal("QtWebEngine::initialize() must be called from the Qt gui thread."); + return; + } -#ifdef Q_OS_MACOS - if (format == QSurfaceFormat()) { - QOpenGLContext testContext; - - // Chromium turns off OpenGL for CoreProfiles with versions < 4.1 - // The newest Mac that only supports 3.3 was released in Mid 2011, - // so it should be safe to request 4.1, but we still double check it - // works in order not to set an invalid default surface format. - format.setVersion(4, 1); - format.setProfile(QSurfaceFormat::CoreProfile); - - testContext.setFormat(format); - if (testContext.create()) { - QOffscreenSurface surface; - surface.setFormat(format); - surface.create(); - - if (testContext.makeCurrent(&surface)) { - // The Cocoa QPA integration allows sharing between OpenGL 3.2 and 4.1 contexts, - // which means even though we requested a 4.1 context, if we only get a 3.2 context, - // it will still work an Chromium will not black list it. - if (testContext.format().version() >= qMakePair(3, 2) && - testContext.format().profile() == QSurfaceFormat::CoreProfile && - !isCurrentContextSoftware()) { - QSurfaceFormat::setDefaultFormat(format); - } else { - qWarning("The available OpenGL surface format was either not version 3.2 or higher or not a Core Profile.\n" - "Chromium on macOS will fall back to software rendering in this case.\n" - "Hardware acceleration and features such as WebGL will not be available."); - format = QSurfaceFormat::defaultFormat(); - } - testContext.doneCurrent(); + if (shareContext) + return; + + shareContext = new QOpenGLContext; + QSurfaceFormat format = QSurfaceFormat::defaultFormat(); + +#if defined(Q_OS_MACOS) + if (format == QSurfaceFormat()) { + QOpenGLContext testContext; + + // Chromium turns off OpenGL for CoreProfiles with versions < 4.1 + // The newest Mac that only supports 3.3 was released in Mid 2011, + // so it should be safe to request 4.1, but we still double check it + // works in order not to set an invalid default surface format. + format.setVersion(4, 1); + format.setProfile(QSurfaceFormat::CoreProfile); + + testContext.setFormat(format); + if (testContext.create()) { + QOffscreenSurface surface; + surface.setFormat(format); + surface.create(); + + if (testContext.makeCurrent(&surface)) { + // The Cocoa QPA integration allows sharing between OpenGL 3.2 and 4.1 contexts, + // which means even though we requested a 4.1 context, if we only get a 3.2 + // context, it will still work an Chromium will not black list it. + if (testContext.format().version() >= qMakePair(3, 2) + && testContext.format().profile() == QSurfaceFormat::CoreProfile + && !isCurrentContextSoftware()) { + QSurfaceFormat::setDefaultFormat(format); + } else { + qWarning("The available OpenGL surface format was either not version 3.2 " + "or higher or not a Core Profile.\n" + "Chromium on macOS will fall back to software rendering in this " + "case.\n" + "Hardware acceleration and features such as WebGL will not be " + "available."); + format = QSurfaceFormat::defaultFormat(); + } + testContext.doneCurrent(); + } + surface.destroy(); + } + } else { + // The user explicitly requested a specific surface format that does not fit Chromium's + // requirements. Warn them about this. + if (format.version() < qMakePair(3, 2) + || format.profile() != QSurfaceFormat::CoreProfile) { + qWarning("An OpenGL surfcace format was requested that is either not version 3.2 " + "or higher or a not Core Profile.\n" + "Chromium on macOS will fall back to software rendering in this case.\n" + "Hardware acceleration and features such as WebGL will not be available."); } - surface.destroy(); - } - } else { - // The user explicitly requested a specific surface format that does not fit Chromium's requirements. Warn them about this. - if (format.version() < qMakePair(3,2) || format.profile() != QSurfaceFormat::CoreProfile) { - qWarning("An OpenGL surfcace format was requested that is either not version 3.2 or higher or a not Core Profile.\n" - "Chromium on macOS will fall back to software rendering in this case.\n" - "Hardware acceleration and features such as WebGL will not be available."); } - } #endif - shareContext->setFormat(format); - shareContext->create(); - qAddPostRoutine(deleteShareContext); - qt_gl_set_global_share_context(shareContext); + shareContext->setFormat(format); + shareContext->create(); + qAddPostRoutine(deleteShareContext); + qt_gl_set_global_share_context(shareContext); + + // Classes like QOpenGLWidget check for the attribute + app->setAttribute(Qt::AA_ShareOpenGLContexts); + } + +#if defined(Q_OS_MACOS) + // Check that the default QSurfaceFormat OpenGL profile is compatible with the global OpenGL + // shared context profile, otherwise this could lead to a nasty crash. + QSurfaceFormat sharedFormat = qt_gl_global_share_context()->format(); + QSurfaceFormat defaultFormat = QSurfaceFormat::defaultFormat(); + + if (defaultFormat.profile() != sharedFormat.profile() + && defaultFormat.profile() == QSurfaceFormat::CoreProfile + && defaultFormat.version() >= qMakePair(3, 2)) { + qFatal("QWebEngine: Default QSurfaceFormat OpenGL profile is not compatible with the " + "global shared context OpenGL profile. Please make sure you set a compatible " + "QSurfaceFormat before the QtGui application instance is created."); + } +#endif - // Classes like QOpenGLWidget check for the attribute - app->setAttribute(Qt::AA_ShareOpenGLContexts); #endif // QT_CONFIG(opengl) } } // namespace QtWebEngineCore diff --git a/src/core/api/qwebenginecallback_p.h b/src/core/api/qwebenginecallback_p.h index 133a86f6d..9cc25b7fd 100644 --- a/src/core/api/qwebenginecallback_p.h +++ b/src/core/api/qwebenginecallback_p.h @@ -244,7 +244,7 @@ inline 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((QTypeInfo<QWebEngineCallback<x>>::isRelocatable)); FOR_EACH_TYPE(CHECK_RELOCATABLE) #undef CHECK_RELOCATABLE diff --git a/src/core/api/qwebenginecertificateerror.cpp b/src/core/api/qwebenginecertificateerror.cpp new file mode 100644 index 000000000..40c9a1c7b --- /dev/null +++ b/src/core/api/qwebenginecertificateerror.cpp @@ -0,0 +1,194 @@ +/**************************************************************************** +** +** 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 "qwebenginecertificateerror.h" + +#include "certificate_error_controller.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QWebEngineCertificateError + \brief The QWebEngineCertificateError class provides information about a certificate error. + \since 5.4 + \inmodule QtWebEngineCore + + Provides information about a certificate error. This class is used as a parameter of + QWebEnginePage::certificateError(). +*/ + +/*! \internal +*/ +QWebEngineCertificateError::QWebEngineCertificateError( + const QSharedPointer<QtWebEngineCore::CertificateErrorController> &controller) + : d(controller) +{ +} + +QWebEngineCertificateError::QWebEngineCertificateError(const QWebEngineCertificateError &) = default; + +QWebEngineCertificateError& QWebEngineCertificateError::operator=(const QWebEngineCertificateError &) = default; + +/*! \internal +*/ +QWebEngineCertificateError::~QWebEngineCertificateError() = default; + +/*! + \enum QWebEngineCertificateError::Type + + This enum describes the type of certificate error encountered. + + The values of this enum type match the SSL errors Chromium provides. + QSslError::SslError values are not used directly, because the Qt error + categories cannot be mapped to the Chromium error categories. + + \value SslPinnedKeyNotInCertificateChain The certificate did not match the built-in public keys + pinned for the host name. + \value CertificateCommonNameInvalid The certificate's common name did not match the host name. + \value CertificateDateInvalid The certificate is not valid at the current date and time. + \value CertificateAuthorityInvalid The certificate is not signed by a trusted authority. + \value CertificateContainsErrors The certificate contains errors. + \value CertificateNoRevocationMechanism The certificate has no mechanism for determining if it has been revoked. + \value CertificateUnableToCheckRevocation Revocation information for the certificate is not available. + \value CertificateRevoked The certificate has been revoked. + \value CertificateInvalid The certificate is invalid. + \value CertificateWeakSignatureAlgorithm The certificate is signed using a weak signature algorithm. + \value CertificateNonUniqueName The host name specified in the certificate is not unique. + \value CertificateWeakKey The certificate contains a weak key. + \value CertificateNameConstraintViolation The certificate claimed DNS names that are in violation of name constraints. + \value CertificateValidityTooLong The certificate has a validity period that is too long. (Added in Qt 5.7) + \value CertificateTransparencyRequired Certificate Transparency was required for this connection, but the server + did not provide CT information that complied with the policy. (Added in Qt 5.8) + \value CertificateKnownInterceptionBlocked The certificate is known to be + used for interception by an entity other the device owner. (Added in + 5.15) + \value SslObsoleteVersion The connection uses an obsolete version of SSL/TLS. (Added in Qt 6.0) +*/ + +/*! + Returns whether this error can be overridden and accepted. + + \sa error(), description() +*/ +bool QWebEngineCertificateError::isOverridable() const +{ + return d->overridable(); +} + +/*! + Returns the URL that triggered the error. + + \sa error(), description() +*/ +QUrl QWebEngineCertificateError::url() const +{ + return d->url(); +} + +/*! + Returns the type of the error. + + \sa description(), isOverridable() +*/ +QWebEngineCertificateError::Type QWebEngineCertificateError::type() const +{ + return d->error(); +} + +/*! + Returns a short localized human-readable description of the error. + + \sa error(), url(), isOverridable() +*/ +QString QWebEngineCertificateError::description() const +{ + return d->errorString(); +} + +/*! + \since 5.14 + + Marks the certificate error for delayed handling. + + This function should be called when there is a need to postpone the decision whether to accept a + certificate, for example, while waiting for user input. When called, the function pauses the + URL request until acceptCertificate() or rejectCertificate() is called. + + \note It is only possible to defer overridable certificate errors. + + \sa isOverridable(), deferred() +*/ +void QWebEngineCertificateError::defer() +{ + d->defer(); +} + +/*! + \since 5.14 + + Accepts the certificate and continues the loading of the requested URL. +*/ +void QWebEngineCertificateError::acceptCertificate() +{ + d->ignoreCertificateError(); +} + +/*! + \since 5.14 + + Rejects the certificate and aborts the loading of the requested URL. +*/ +void QWebEngineCertificateError::rejectCertificate() +{ + d->rejectCertificate(); +} + +/*! + \since 5.14 + + Returns the peer's chain of digital certificates. + + Chain starts with the peer's immediate certificate and ending with the CA's certificate. +*/ +QList<QSslCertificate> QWebEngineCertificateError::certificateChain() const +{ + return d->certificateChain(); +} + +QT_END_NAMESPACE diff --git a/src/core/api/qwebenginecertificateerror.h b/src/core/api/qwebenginecertificateerror.h new file mode 100644 index 000000000..ffcebaf9b --- /dev/null +++ b/src/core/api/qwebenginecertificateerror.h @@ -0,0 +1,113 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QWEBENGINECERTIFICATEERROR_H +#define QWEBENGINECERTIFICATEERROR_H + +#include <QtWebEngineCore/qtwebenginecoreglobal.h> + +#include <QtCore/qsharedpointer.h> +#include <QtCore/qurl.h> +#include <QtNetwork/QSslCertificate> + +namespace QtWebEngineCore { +class WebContentsDelegateQt; +class CertificateErrorController; +} + +QT_BEGIN_NAMESPACE + +class Q_WEBENGINECORE_EXPORT QWebEngineCertificateError { + Q_GADGET + Q_PROPERTY(QUrl url READ url CONSTANT FINAL) + Q_PROPERTY(Type type READ type CONSTANT FINAL) + Q_PROPERTY(QString description READ description CONSTANT FINAL) + Q_PROPERTY(bool overridable READ isOverridable CONSTANT FINAL) + +public: + QWebEngineCertificateError(const QWebEngineCertificateError &other); + QWebEngineCertificateError& operator=(const QWebEngineCertificateError &other); + ~QWebEngineCertificateError(); + + // Keep this identical to NET_ERROR in net_error_list.h, or add mapping layer. + enum Type { + SslPinnedKeyNotInCertificateChain = -150, + CertificateCommonNameInvalid = -200, + CertificateDateInvalid = -201, + CertificateAuthorityInvalid = -202, + CertificateContainsErrors = -203, + CertificateNoRevocationMechanism = -204, + CertificateUnableToCheckRevocation = -205, + CertificateRevoked = -206, + CertificateInvalid = -207, + CertificateWeakSignatureAlgorithm = -208, + CertificateNonUniqueName = -210, + CertificateWeakKey = -211, + CertificateNameConstraintViolation = -212, + CertificateValidityTooLong = -213, + CertificateTransparencyRequired = -214, + CertificateSymantecLegacy = -215, + CertificateKnownInterceptionBlocked = -217, + SslObsoleteVersion = -218, + }; + Q_ENUM(Type) + + Type type() const; + QUrl url() const; + bool isOverridable() const; + QString description() const; + + Q_INVOKABLE void defer(); + Q_INVOKABLE void rejectCertificate(); + Q_INVOKABLE void acceptCertificate(); + + QList<QSslCertificate> certificateChain() const; + +private: + friend class QtWebEngineCore::WebContentsDelegateQt; + QWebEngineCertificateError( + const QSharedPointer<QtWebEngineCore::CertificateErrorController> &controller); + QSharedPointer<QtWebEngineCore::CertificateErrorController> d; +}; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QWebEngineCertificateError) + +#endif // QWEBENGINECERTIFICATEERROR_H diff --git a/src/core/api/qwebengineclientcertificatestore.cpp b/src/core/api/qwebengineclientcertificatestore.cpp index 84f273328..462a63b26 100644 --- a/src/core/api/qwebengineclientcertificatestore.cpp +++ b/src/core/api/qwebengineclientcertificatestore.cpp @@ -88,9 +88,9 @@ void QWebEngineClientCertificateStore::add(const QSslCertificate &certificate, c Returns an empty list if the store does not contain any certificates. */ -QVector<QSslCertificate> QWebEngineClientCertificateStore::certificates() const +QList<QSslCertificate> QWebEngineClientCertificateStore::certificates() const { - QVector<QSslCertificate> certificateList; + QList<QSslCertificate> certificateList; for (auto data : qAsConst(m_storeData->extraCerts)) certificateList.append(data->certificate); return certificateList; diff --git a/src/core/api/qwebengineclientcertificatestore.h b/src/core/api/qwebengineclientcertificatestore.h index a4c83bb2e..a9282f0fb 100644 --- a/src/core/api/qwebengineclientcertificatestore.h +++ b/src/core/api/qwebengineclientcertificatestore.h @@ -41,8 +41,10 @@ #define QWEBENGINECLIENTCERTIFICATESTORE_H #include <QtWebEngineCore/qtwebenginecoreglobal.h> +#include <QtNetwork/qtnetwork-config.h> -#include <QtCore/qvector.h> +#if QT_CONFIG(ssl) +#include <QtCore/qlist.h> #include <QtNetwork/qsslcertificate.h> #include <QtNetwork/qsslkey.h> @@ -53,13 +55,11 @@ class ProfileAdapter; 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; + QList<QSslCertificate> certificates() const; void remove(const QSslCertificate &certificate); void clear(); @@ -72,8 +72,7 @@ private: QtWebEngineCore::ClientCertificateStoreData *m_storeData; }; -#endif // QT_CONFIG(ssl) - QT_END_NAMESPACE +#endif // QT_CONFIG(ssl) #endif // QWebEngineClientCertificateStore_H diff --git a/src/core/api/qwebenginecontextmenurequest.cpp b/src/core/api/qwebenginecontextmenurequest.cpp new file mode 100644 index 000000000..62a328b72 --- /dev/null +++ b/src/core/api/qwebenginecontextmenurequest.cpp @@ -0,0 +1,296 @@ +/**************************************************************************** +** +** Copyright (C) 2020 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 "qwebenginecontextmenurequest.h" +#include "qwebenginecontextmenurequest_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QWebEngineContextMenuRequest + \since 6.0 + \brief The QWebEngineContextMenuRequest class provides request for populating or extending a context menu with actions. + + \inmodule QtWebEngineCore + + QWebEngineContextMenuRequest is returned by QWebEngineView::lastContextMenuRequest() after a context menu event, + and contains information about where the context menu event took place. This is also in the context + in which any context specific QWebEnginePage::WebAction will be performed. +*/ + +/*! + \enum QWebEngineContextMenuRequest::MediaType + \readonly + \since 6.0 + + This enum describes the media type of the context menu request if any. + + \value MediaTypeNone The context is not a media type. + \value MediaTypeImage The context is an image element. + \value MediaTypeVideo The context is a video element. + \value MediaTypeAudio The context is an audio element. + \value MediaTypeCanvas The context is a canvas element. + \value MediaTypeFile The context is a file. + \value MediaTypePlugin The context is a plugin element. +*/ + +/*! + \enum QWebEngineContextMenuRequest::EditFlag + \readonly + \since 6.0 + + The available edit operations in the current context menu request. + + \value CanUndo Undo is available. + \value CanRedo Redo is available. + \value CanCut Cut is available. + \value CanCopy Copy is available. + \value CanPaste Paste is available. + \value CanDelete Delete is available. + \value CanSelectAll Select All is available. + \value CanTranslate Translate is available. + \value CanEditRichly Context is richly editable. +*/ + +/*! + \enum QWebEngineContextMenuRequest::MediaFlag + \readonly + \since 6.0 + + The current media element's status and its available operations. + \c MediaNone if the selected web page content is not a media element. + + \value MediaInError An error occurred. + \value MediaPaused Media is paused. + \value MediaMuted Media is muted. + \value MediaLoop Media can be looped. + \value MediaCanSave Media can be saved. + \value MediaHasAudio Media has audio. + \value MediaCanToggleControls Media can show controls. + \value MediaControls Media controls are shown. + \value MediaCanPrint Media is printable. + \value MediaCanRotate Media is rotatable. +*/ + +/*! + \internal +*/ +QWebEngineContextMenuRequest::QWebEngineContextMenuRequest( + QWebEngineContextMenuRequestPrivate *request) + : d(request) +{ +} + +/*! + Destroys the context menu request. +*/ +QWebEngineContextMenuRequest::~QWebEngineContextMenuRequest() = default; + +/*! + Returns the position of the context menu request, usually the mouse + position where the context menu event was triggered. +*/ +QPoint QWebEngineContextMenuRequest::position() const +{ + return d->m_position; +} + +/*! + Returns the selected text of the context menu request. +*/ +QString QWebEngineContextMenuRequest::selectedText() const +{ + return d->m_selectedText; +} + +/*! + Returns the text of a link if the context menu request was requested for a link. +*/ +QString QWebEngineContextMenuRequest::linkText() const +{ + return d->m_linkText; +} + +/*! + Returns the URL of a link if the menu context request is a link. + It is not guaranteed to be a valid URL. +*/ +QUrl QWebEngineContextMenuRequest::linkUrl() const +{ + return d->m_unfilteredLinkUrl; +} + +/*! + If the context menu request is a media element, returns the URL of that media. +*/ +QUrl QWebEngineContextMenuRequest::mediaUrl() const +{ + return d->m_mediaUrl; +} + +/*! + Returns the type of the media element or \c MediaTypeNone + if the context menu requestis not a media element. +*/ +QWebEngineContextMenuRequest::MediaType QWebEngineContextMenuRequest::mediaType() const +{ + return static_cast<QWebEngineContextMenuRequest::MediaType>(d->m_mediaType); +} + +/*! + Returns \c true if the context menu request is editable by the user; + otherwise returns \c false. +*/ +bool QWebEngineContextMenuRequest::isContentEditable() const +{ + return d->m_isEditable; +} + +/*! + If the menu context request is a word considered misspelled by the spell-checker, + returns the misspelled word. + + For possible replacements of the word, see spellCheckerSuggestions(). +*/ +QString QWebEngineContextMenuRequest::misspelledWord() const +{ + return d->m_misspelledWord; +} + + +/*! + If the menu context request is a word considered misspelled by the spell-checker, + returns a list of suggested replacements for misspelledWord(). +*/ +QStringList QWebEngineContextMenuRequest::spellCheckerSuggestions() const +{ + return d->m_spellCheckerSuggestions; +} + +/*! + TODO: needs api in page +*/ +bool QWebEngineContextMenuRequest::isAccepted() const +{ + return d->m_accepted; +} + +/*! + TODO: needs api in page +*/ +void QWebEngineContextMenuRequest::setAccepted(bool accepted) +{ + d->m_accepted = accepted; +} + +/*! + Returns the current media element's status and its available operations. + \c MediaNone if the selected web page content is not a media element. +*/ +QWebEngineContextMenuRequest::MediaFlags QWebEngineContextMenuRequest::mediaFlags() const +{ + return static_cast<QWebEngineContextMenuRequest::MediaFlags>(d->m_mediaFlags); +} + +/*! + Returns the available edit operations in the current context + or \c CanDoNone if no actions are available. +*/ +QWebEngineContextMenuRequest::EditFlags QWebEngineContextMenuRequest::editFlags() const +{ + return static_cast<QWebEngineContextMenuRequest::EditFlags>(d->m_editFlags); +} + +/*! + \internal +*/ +QUrl QWebEngineContextMenuRequest::filteredLinkUrl() const +{ + return d->m_filteredLinkUrl; +} + +/*! + \internal +*/ +QString QWebEngineContextMenuRequest::altText() const +{ + return d->m_altText; +} + +/*! + \internal +*/ +QString QWebEngineContextMenuRequest::titleText() const +{ + return d->m_titleText; +} + +/*! + \internal +*/ +QUrl QWebEngineContextMenuRequest::referrerUrl() const +{ + return !d->m_frameUrl.isEmpty() ? d->m_frameUrl : d->m_pageUrl; +} + +/*! + \internal +*/ +QtWebEngineCore::ReferrerPolicy QWebEngineContextMenuRequest::referrerPolicy() const +{ + return d->m_referrerPolicy; +} + +/*! + \internal +*/ +QString QWebEngineContextMenuRequest::suggestedFileName() const +{ + return d->m_suggestedFileName; +} + +/*! + \internal +*/ +bool QWebEngineContextMenuRequest::hasImageContent() const +{ + return d->m_hasImageContent; +} + +QT_END_NAMESPACE diff --git a/src/core/api/qwebenginecontextmenurequest.h b/src/core/api/qwebenginecontextmenurequest.h new file mode 100644 index 000000000..bc8095dc9 --- /dev/null +++ b/src/core/api/qwebenginecontextmenurequest.h @@ -0,0 +1,168 @@ +/**************************************************************************** +** +** Copyright (C) 2020 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 QWEBENGINECONTEXTMENUREQUEST_H +#define QWEBENGINECONTEXTMENUREQUEST_H + +#include <QtWebEngineCore/qtwebenginecoreglobal.h> +#include <QtCore/QObject> +#include <QtCore/QUrl> +#include <QtCore/QPoint> +#include <QScopedPointer> + +namespace QtWebEngineCore { +class RenderViewContextMenuQt; +class WebContentsViewQt; + +// Must match blink::WebReferrerPolicy +enum class ReferrerPolicy { + Always, + Default, + NoReferrerWhenDowngrade, + Never, + Origin, + OriginWhenCrossOrigin, + NoReferrerWhenDowngradeOriginWhenCrossOrigin, + SameOrigin, + StrictOrigin, + Last = StrictOrigin, +}; +} + +QT_BEGIN_NAMESPACE + +class QWebEngineContextMenuRequestPrivate; +class Q_WEBENGINECORE_EXPORT QWebEngineContextMenuRequest : public QObject +{ + Q_OBJECT +public: + enum MediaType { + MediaTypeNone, + MediaTypeImage, + MediaTypeVideo, + MediaTypeAudio, + MediaTypeCanvas, + MediaTypeFile, + MediaTypePlugin + }; + Q_ENUM(MediaType) + + // Must match QWebEngineCore::WebEngineContextMenuData::MediaFlags: + enum MediaFlag { + MediaInError = 0x1, + MediaPaused = 0x2, + MediaMuted = 0x4, + MediaLoop = 0x8, + MediaCanSave = 0x10, + MediaHasAudio = 0x20, + MediaCanToggleControls = 0x40, + MediaControls = 0x80, + MediaCanPrint = 0x100, + MediaCanRotate = 0x200, + }; + Q_DECLARE_FLAGS(MediaFlags, MediaFlag) + Q_FLAG(MediaFlags) + + // Must match QWebEngineCore::WebEngineContextMenuData::EditFlags: + enum EditFlag { + CanUndo = 0x1, + CanRedo = 0x2, + CanCut = 0x4, + CanCopy = 0x8, + CanPaste = 0x10, + CanDelete = 0x20, + CanSelectAll = 0x40, + CanTranslate = 0x80, + CanEditRichly = 0x100, + }; + Q_DECLARE_FLAGS(EditFlags, EditFlag) + Q_FLAG(EditFlags) + + Q_PROPERTY(QPoint position READ position CONSTANT FINAL) + Q_PROPERTY(QString selectedText READ selectedText CONSTANT FINAL) + Q_PROPERTY(QString linkText READ linkText CONSTANT FINAL) + Q_PROPERTY(QUrl linkUrl READ linkUrl CONSTANT FINAL) + Q_PROPERTY(QUrl mediaUrl READ mediaUrl CONSTANT FINAL) + Q_PROPERTY(MediaType mediaType READ mediaType CONSTANT FINAL) + Q_PROPERTY(bool isContentEditable READ isContentEditable CONSTANT FINAL) + Q_PROPERTY(QString misspelledWord READ misspelledWord CONSTANT FINAL) + Q_PROPERTY(QStringList spellCheckerSuggestions READ spellCheckerSuggestions CONSTANT FINAL) + Q_PROPERTY(bool accepted READ isAccepted WRITE setAccepted FINAL) + Q_PROPERTY(MediaFlags mediaFlags READ mediaFlags CONSTANT FINAL REVISION 1) + Q_PROPERTY(EditFlags editFlags READ editFlags CONSTANT FINAL REVISION 1) + + virtual ~QWebEngineContextMenuRequest(); + QPoint position() const; + QString selectedText() const; + QString linkText() const; + QUrl linkUrl() const; + QUrl mediaUrl() const; + MediaType mediaType() const; + bool isContentEditable() const; + QString misspelledWord() const; + QStringList spellCheckerSuggestions() const; + bool isAccepted() const; + void setAccepted(bool accepted); + MediaFlags mediaFlags() const; + EditFlags editFlags() const; + +private: + QUrl filteredLinkUrl() const; + QString altText() const; + QString titleText() const; + QUrl referrerUrl() const; + QtWebEngineCore::ReferrerPolicy referrerPolicy() const; + bool hasImageContent() const; + QString suggestedFileName() const; + +private: + QWebEngineContextMenuRequest(QWebEngineContextMenuRequestPrivate *d); + QScopedPointer<QWebEngineContextMenuRequestPrivate> d; + friend class QtWebEngineCore::WebContentsViewQt; + friend class QtWebEngineCore::RenderViewContextMenuQt; + friend class QQuickWebEngineViewPrivate; + friend class QQuickWebEngineView; + friend class ContextMenuRequestJSWrapper; + friend class QWebEngineViewPrivate; + friend class QWebEnginePage; +}; + +QT_END_NAMESPACE + +#endif // QWEBENGINECONTEXTMENUREQUEST_H diff --git a/src/core/certificate_error_controller_p.h b/src/core/api/qwebenginecontextmenurequest_p.h index b0b0bc658..c7b98a871 100644 --- a/src/core/certificate_error_controller_p.h +++ b/src/core/api/qwebenginecontextmenurequest_p.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtWebEngine module of the Qt Toolkit. @@ -37,8 +37,8 @@ ** ****************************************************************************/ -#ifndef CERTIFICATE_ERROR_CONTROLLER_P_H -#define CERTIFICATE_ERROR_CONTROLLER_P_H +#ifndef QWEBENGINECONTEXTMENUREQUEST_P_H +#define QWEBENGINECONTEXTMENUREQUEST_P_H // // W A R N I N G @@ -51,29 +51,43 @@ // We mean it. // -#include "content/public/browser/content_browser_client.h" - -#include "certificate_error_controller.h" +#include "qtwebenginecoreglobal_p.h" +#include "qwebenginecontextmenurequest.h" +#include <QPoint> +#include <QUrl> QT_BEGIN_NAMESPACE -class CertificateErrorControllerPrivate { +class QWebEngineContextMenuRequestPrivate +{ public: - CertificateErrorControllerPrivate(int cert_error, const net::SSLInfo& ssl_info, const GURL& request_url, bool main_frame, bool fatal_error, bool strict_enforcement, base::OnceCallback<void(content::CertificateRequestResultType)> callback); - - void accept(bool accepted); - - CertificateErrorController::CertificateError certError; - const QUrl requestUrl; - QDateTime validStart; - QDateTime validExpiry; - CertificateErrorController::ResourceType resourceType; - bool fatalError; - bool strictEnforcement; - base::OnceCallback<void(content::CertificateRequestResultType)> callback; - QList<QSslCertificate> certificateChain; + bool m_accepted = false; + bool m_hasImageContent = false; + bool m_isEditable = false; + bool m_isSpellCheckerEnabled = false; + uint m_mediaType = 0; + uint m_mediaFlags = 0; + uint m_editFlags = 0; + QPoint m_position; + QUrl m_filteredLinkUrl; + QUrl m_unfilteredLinkUrl; + QUrl m_mediaUrl; + QString m_altText; + QString m_linkText; + QString m_titleText; + QString m_selectedText; + QString m_suggestedFileName; + QString m_misspelledWord; + QStringList m_spellCheckerSuggestions; + QUrl m_pageUrl; + QUrl m_frameUrl; + QtWebEngineCore::ReferrerPolicy m_referrerPolicy = QtWebEngineCore::ReferrerPolicy::Default; + // Some likely candidates for future additions as we add support for the related actions: + // bool isImageBlocked; + // <enum tbd> mediaType; + // ... }; QT_END_NAMESPACE -#endif // CERTIFICATE_ERROR_CONTROLLER_P_H +#endif diff --git a/src/core/api/qwebenginecookiestore_p.h b/src/core/api/qwebenginecookiestore_p.h index a79e2b095..e6fa245c2 100644 --- a/src/core/api/qwebenginecookiestore_p.h +++ b/src/core/api/qwebenginecookiestore_p.h @@ -56,7 +56,7 @@ #include "qwebenginecallback_p.h" #include "qwebenginecookiestore.h" -#include <QVector> +#include <QList> #include <QNetworkCookie> #include <QUrl> @@ -79,7 +79,7 @@ class Q_WEBENGINECORE_PRIVATE_EXPORT QWebEngineCookieStorePrivate { public: QtWebEngineCore::CallbackDirectory callbackDirectory; std::function<bool(const QWebEngineCookieStore::FilterRequest &)> filterCallback; - QVector<CookieData> m_pendingUserCookies; + QList<CookieData> m_pendingUserCookies; quint64 m_nextCallbackId; bool m_deleteSessionCookiesPending; bool m_deleteAllCookiesPending; diff --git a/src/core/api/qwebenginedownloadrequest.cpp b/src/core/api/qwebenginedownloadrequest.cpp new file mode 100644 index 000000000..bf4994a64 --- /dev/null +++ b/src/core/api/qwebenginedownloadrequest.cpp @@ -0,0 +1,680 @@ +/**************************************************************************** +** +** 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 "qwebenginedownloadrequest.h" +#include "qwebenginedownloadrequest_p.h" + +#include "profile_adapter.h" + +#include <QDir> +#include "QFileInfo" + +QT_BEGIN_NAMESPACE + +using QtWebEngineCore::ProfileAdapterClient; + +ASSERT_ENUMS_MATCH(ProfileAdapterClient::NoReason, QWebEngineDownloadRequest::NoReason) +ASSERT_ENUMS_MATCH(ProfileAdapterClient::FileFailed, QWebEngineDownloadRequest::FileFailed) +ASSERT_ENUMS_MATCH(ProfileAdapterClient::FileAccessDenied, QWebEngineDownloadRequest::FileAccessDenied) +ASSERT_ENUMS_MATCH(ProfileAdapterClient::FileNoSpace, QWebEngineDownloadRequest::FileNoSpace) +ASSERT_ENUMS_MATCH(ProfileAdapterClient::FileNameTooLong, QWebEngineDownloadRequest::FileNameTooLong) +ASSERT_ENUMS_MATCH(ProfileAdapterClient::FileTooLarge, QWebEngineDownloadRequest::FileTooLarge) +ASSERT_ENUMS_MATCH(ProfileAdapterClient::FileVirusInfected, QWebEngineDownloadRequest::FileVirusInfected) +ASSERT_ENUMS_MATCH(ProfileAdapterClient::FileTransientError, QWebEngineDownloadRequest::FileTransientError) +ASSERT_ENUMS_MATCH(ProfileAdapterClient::FileBlocked, QWebEngineDownloadRequest::FileBlocked) +ASSERT_ENUMS_MATCH(ProfileAdapterClient::FileSecurityCheckFailed, QWebEngineDownloadRequest::FileSecurityCheckFailed) +ASSERT_ENUMS_MATCH(ProfileAdapterClient::FileTooShort, QWebEngineDownloadRequest::FileTooShort) +ASSERT_ENUMS_MATCH(ProfileAdapterClient::FileHashMismatch, QWebEngineDownloadRequest::FileHashMismatch) +ASSERT_ENUMS_MATCH(ProfileAdapterClient::NetworkFailed, QWebEngineDownloadRequest::NetworkFailed) +ASSERT_ENUMS_MATCH(ProfileAdapterClient::NetworkTimeout, QWebEngineDownloadRequest::NetworkTimeout) +ASSERT_ENUMS_MATCH(ProfileAdapterClient::NetworkDisconnected, QWebEngineDownloadRequest::NetworkDisconnected) +ASSERT_ENUMS_MATCH(ProfileAdapterClient::NetworkServerDown, QWebEngineDownloadRequest::NetworkServerDown) +ASSERT_ENUMS_MATCH(ProfileAdapterClient::NetworkInvalidRequest, QWebEngineDownloadRequest::NetworkInvalidRequest) +ASSERT_ENUMS_MATCH(ProfileAdapterClient::ServerFailed, QWebEngineDownloadRequest::ServerFailed) +//ASSERT_ENUMS_MATCH(ProfileAdapterClient::ServerNoRange, QWebEngineDownloadRequest::ServerNoRange) +ASSERT_ENUMS_MATCH(ProfileAdapterClient::ServerBadContent, QWebEngineDownloadRequest::ServerBadContent) +ASSERT_ENUMS_MATCH(ProfileAdapterClient::ServerUnauthorized, QWebEngineDownloadRequest::ServerUnauthorized) +ASSERT_ENUMS_MATCH(ProfileAdapterClient::ServerCertProblem, QWebEngineDownloadRequest::ServerCertProblem) +ASSERT_ENUMS_MATCH(ProfileAdapterClient::ServerForbidden, QWebEngineDownloadRequest::ServerForbidden) +ASSERT_ENUMS_MATCH(ProfileAdapterClient::ServerUnreachable, QWebEngineDownloadRequest::ServerUnreachable) +ASSERT_ENUMS_MATCH(ProfileAdapterClient::UserCanceled, QWebEngineDownloadRequest::UserCanceled) +//ASSERT_ENUMS_MATCH(ProfileAdapterClient::UserShutdown, QWebEngineDownloadRequest::UserShutdown) +//ASSERT_ENUMS_MATCH(ProfileAdapterClient::Crash, QWebEngineDownloadRequest::Crash) + +static inline QWebEngineDownloadRequest::DownloadState toDownloadState(int state) +{ + switch (state) { + case ProfileAdapterClient::DownloadInProgress: + return QWebEngineDownloadRequest::DownloadInProgress; + case ProfileAdapterClient::DownloadCompleted: + return QWebEngineDownloadRequest::DownloadCompleted; + case ProfileAdapterClient::DownloadCancelled: + return QWebEngineDownloadRequest::DownloadCancelled; + case ProfileAdapterClient::DownloadInterrupted: + return QWebEngineDownloadRequest::DownloadInterrupted; + default: + Q_UNREACHABLE(); + return QWebEngineDownloadRequest::DownloadCancelled; + } +} + +static inline QWebEngineDownloadRequest::DownloadInterruptReason toDownloadInterruptReason(int reason) +{ + return static_cast<QWebEngineDownloadRequest::DownloadInterruptReason>(reason); +} + +/*! + \class QWebEngineDownloadRequest + \brief The QWebEngineDownloadRequest class provides information about a download. + + \inmodule QtWebEngineCore + + QWebEngineDownloadRequest models a download throughout its life cycle, starting + with a pending download request and finishing with a completed download. It + can be used, for example, to get information about new downloads, to monitor + progress, and to pause, resume, and cancel downloads. + + Downloads are usually triggered by user interaction on a web page. It is the + QWebEngineProfile's responsibility to notify the application of new download + requests, which it does by emitting the + \l{QWebEngineProfile::downloadRequested}{downloadRequested} signal together + with a newly created QWebEngineDownloadRequest. The application can then + examine this item and decide whether to accept it or not. A signal handler + must explicitly call accept() on the item for \QWE to actually start + downloading and writing data to disk. If no signal handler calls accept(), + then the download request will be automatically rejected and nothing will be + written to disk. + + \note Some properties, such as setting the path and file name where the file + will be saved (see \l downloadDirectory() and \l downloadFileName()), can + only be changed before calling accept(). + + \section2 Object Life Cycle + + All items are guaranteed to be valid during the emission of the + \l{QWebEngineProfile::downloadRequested}{downloadRequested} signal. If + accept() is \e not called by any signal handler, then the item will be + deleted \e immediately after signal emission. This means that the + application \b{must not} keep references to rejected download items. It also + means the application should not use a queued connection to this signal. + + If accept() \e is called by a signal handler, then the QWebEngineProfile + will take ownership of the item. However, it is safe for the application to + delete the item at any time, except during the handling of the + \l{QWebEngineProfile::downloadRequested}{downloadRequested} signal. The + QWebEngineProfile being a long-lived object, it is in fact recommended that + the application delete any items it is no longer interested in. + + \note Deleting an item will also automatically cancel a download since 5.12.2, + but it is recommended to cancel manually before deleting for portability. + + \section2 Web Page Downloads + + In addition to normal file downloads, which consist simply of retrieving + some raw bytes from the network and writing them to disk, \QWE also + supports saving complete web pages, which involves parsing the page's HTML, + downloading any dependent resources, and potentially packaging everything + into a special file format (\l savePageFormat). To check if a download is + for a file or a web page, use \l isSavePageDownload. + + \sa QWebEngineProfile, QWebEngineProfile::downloadRequested, + QWebEnginePage::download, QWebEnginePage::save +*/ + +QWebEngineDownloadRequestPrivate::QWebEngineDownloadRequestPrivate(QtWebEngineCore::ProfileAdapter *adapter, const QUrl &url) + : m_profileAdapter(adapter) + , downloadFinished(false) + , downloadId(-1) + , downloadState(QWebEngineDownloadRequest::DownloadCancelled) + , savePageFormat(QWebEngineDownloadRequest::MimeHtmlSaveFormat) + , interruptReason(QWebEngineDownloadRequest::NoReason) + , downloadUrl(url) + , downloadPaused(false) + , isCustomFileName(false) + , totalBytes(-1) + , receivedBytes(0) + , isSavePageDownload(false) + , page(nullptr) +{ +} + +QWebEngineDownloadRequestPrivate::~QWebEngineDownloadRequestPrivate() +{ +} + +void QWebEngineDownloadRequestPrivate::update(const ProfileAdapterClient::DownloadItemInfo &info) +{ + Q_Q(QWebEngineDownloadRequest); + + Q_ASSERT(downloadState != QWebEngineDownloadRequest::DownloadRequested); + + if (toDownloadInterruptReason(info.downloadInterruptReason) != interruptReason) { + interruptReason = toDownloadInterruptReason(info.downloadInterruptReason); + Q_EMIT q->interruptReasonChanged(); + } + if (toDownloadState(info.state) != downloadState) { + downloadState = toDownloadState(info.state); + Q_EMIT q->stateChanged(downloadState); + } + + if (info.receivedBytes != receivedBytes || info.totalBytes != totalBytes) { + + if (info.receivedBytes != receivedBytes) { + receivedBytes = info.receivedBytes; + Q_EMIT q->receivedBytesChanged(); + } + if (info.totalBytes != totalBytes) { + totalBytes = info.totalBytes; + Q_EMIT q->totalBytesChanged(); + } + Q_EMIT q->downloadProgress(receivedBytes, totalBytes); + } + + if (info.done) + setFinished(); + + if (downloadPaused != info.paused) { + downloadPaused = info.paused; + Q_EMIT q->isPausedChanged(); + } +} + +void QWebEngineDownloadRequestPrivate::setFinished() +{ + if (downloadFinished) + return; + + downloadFinished = true; + Q_EMIT q_ptr->isFinishedChanged(); +} + +/*! + Accepts the current download request, which will start the download. + + If the item is in the \l DownloadRequested state, then it will transition + into the \l DownloadInProgress state and the downloading will begin. If the + item is in any other state, then nothing will happen. + + \sa finished(), stateChanged() +*/ + +void QWebEngineDownloadRequest::accept() +{ + Q_D(QWebEngineDownloadRequest); + + if (d->downloadState != QWebEngineDownloadRequest::DownloadRequested) + return; + + d->downloadState = QWebEngineDownloadRequest::DownloadInProgress; + Q_EMIT stateChanged(d->downloadState); +} + +/*! + Cancels the current download. + + If the item is in the \l DownloadInProgress state, then it will transition + into the \l DownloadCancelled state, the downloading will stop, and partially + downloaded files will be deleted from disk. + + If the item is in the \l DownloadCompleted state, then nothing will happen. + If the item is in any other state, then it will transition into the \l + DownloadCancelled state without further effect. + + \sa finished(), stateChanged() +*/ + +void QWebEngineDownloadRequest::cancel() +{ + Q_D(QWebEngineDownloadRequest); + + QWebEngineDownloadRequest::DownloadState state = d->downloadState; + + if (state == QWebEngineDownloadRequest::DownloadCompleted + || state == QWebEngineDownloadRequest::DownloadCancelled) + return; + + // We directly cancel the download request if the user cancels + // before it even started, so no need to notify the profile here. + if (state == QWebEngineDownloadRequest::DownloadInProgress) { + if (d->m_profileAdapter) + d->m_profileAdapter->cancelDownload(d->downloadId); + } else { + d->downloadState = QWebEngineDownloadRequest::DownloadCancelled; + Q_EMIT stateChanged(d->downloadState); + d->setFinished(); + } +} + +/*! + Pauses the download. + + Has no effect if the state is not \l DownloadInProgress. Does not change the + state. + + \sa resume(), isPaused() +*/ + +void QWebEngineDownloadRequest::pause() +{ + Q_D(QWebEngineDownloadRequest); + + QWebEngineDownloadRequest::DownloadState state = d->downloadState; + + if (state != QWebEngineDownloadRequest::DownloadInProgress) + return; + + if (d->m_profileAdapter) + d->m_profileAdapter->pauseDownload(d->downloadId); +} + +/*! + Resumes the current download if it was paused or interrupted. + + Has no effect if the state is not \l DownloadInProgress or \l + DownloadInterrupted. Does not change the state. + + \sa pause(), isPaused(), state() +*/ +void QWebEngineDownloadRequest::resume() +{ + Q_D(QWebEngineDownloadRequest); + + QWebEngineDownloadRequest::DownloadState state = d->downloadState; + + if (d->downloadFinished || (state != QWebEngineDownloadRequest::DownloadInProgress && state != QWebEngineDownloadRequest::DownloadInterrupted)) + return; + if (d->m_profileAdapter) + d->m_profileAdapter->resumeDownload(d->downloadId); +} + +/*! + Returns the download item's ID. +*/ + +quint32 QWebEngineDownloadRequest::id() const +{ + Q_D(const QWebEngineDownloadRequest); + return d->downloadId; +} + +/*! + \fn void QWebEngineDownloadRequest::finished() + + This signal is emitted when the download finishes. + + \sa state(), isFinished() +*/ + +/*! + \fn void QWebEngineDownloadRequest::isPausedChanged(bool isPaused) + + This signal is emitted whenever \a isPaused changes. + + \sa pause(), isPaused() +*/ + +/*! + \fn void QWebEngineDownloadRequest::stateChanged(DownloadState state) + + This signal is emitted whenever the download's \a state changes. + + \sa state(), DownloadState +*/ + +/*! + \fn void QWebEngineDownloadRequest::downloadProgress(qint64 bytesReceived, qint64 bytesTotal) + + This signal is emitted to indicate the progress of the download request. + + The \a bytesReceived parameter indicates the number of bytes received, while + \a bytesTotal indicates the total number of bytes expected to be downloaded. + If the size of the file to be downloaded is not known, \c bytesTotal will be + 0. + + \sa totalBytes(), receivedBytes() +*/ + +/*! + \enum QWebEngineDownloadRequest::DownloadState + + This enum describes the state of the download: + + \value DownloadRequested Download has been requested, but has not been accepted yet. + \value DownloadInProgress Download is in progress. + \value DownloadCompleted Download completed successfully. + \value DownloadCancelled Download has been cancelled. + \value DownloadInterrupted Download has been interrupted (by the server or because of lost + connectivity). +*/ + +/*! + \enum QWebEngineDownloadRequest::SavePageFormat + + This enum describes the format that is used to save a web page. + + \value UnknownSaveFormat This is not a request for downloading a complete web page. + \value SingleHtmlSaveFormat The page is saved as a single HTML page. Resources such as images + are not saved. + \value CompleteHtmlSaveFormat The page is saved as a complete HTML page, for example a directory + containing the single HTML page and the resources. + \value MimeHtmlSaveFormat The page is saved as a complete web page in the MIME HTML format. +*/ + +/*! + \enum QWebEngineDownloadRequest::DownloadInterruptReason + + Describes the reason why a download was interrupted: + + \value NoReason Unknown reason or not interrupted. + \value FileFailed General file operation failure. + \value FileAccessDenied The file cannot be written locally, due to access restrictions. + \value FileNoSpace Insufficient space on the target drive. + \value FileNameTooLong The directory or file name is too long. + \value FileTooLarge The file size exceeds the file system limitation. + \value FileVirusInfected The file is infected with a virus. + \value FileTransientError Temporary problem (for example the file is in use, + out of memory, or too many files are opened at once). + \value FileBlocked The file was blocked due to local policy. + \value FileSecurityCheckFailed An attempt to check the safety of the download + failed due to unexpected reasons. + \value FileTooShort An attempt was made to seek past the end of a file when + opening a file (as part of resuming a previously interrupted download). + \value FileHashMismatch The partial file did not match the expected hash. + + \value NetworkFailed General network failure. + \value NetworkTimeout The network operation has timed out. + \value NetworkDisconnected The network connection has been terminated. + \value NetworkServerDown The server has gone down. + \value NetworkInvalidRequest The network request was invalid (for example, the + original or redirected URL is invalid, has an unsupported scheme, or is disallowed by policy). + + \value ServerFailed General server failure. + \value ServerBadContent The server does not have the requested data. + \value ServerUnauthorized The server did not authorize access to the resource. + \value ServerCertProblem A problem with the server certificate occurred. + \value ServerForbidden Access forbidden by the server. + \value ServerUnreachable Unexpected server response (might indicate that + the responding server may not be the intended server). + \value UserCanceled The user canceled the download. +*/ + +/*! + Returns the download item's current state. + + \sa DownloadState +*/ + +QWebEngineDownloadRequest::DownloadState QWebEngineDownloadRequest::state() const +{ + Q_D(const QWebEngineDownloadRequest); + return d->downloadState; +} + +/*! + Returns the the total amount of data to download in bytes. + + \c -1 means the size is unknown. +*/ + +qint64 QWebEngineDownloadRequest::totalBytes() const +{ + Q_D(const QWebEngineDownloadRequest); + return d->totalBytes; +} + +/*! + Returns the amount of data in bytes that has been downloaded so far. + + \c -1 means the size is unknown. +*/ + +qint64 QWebEngineDownloadRequest::receivedBytes() const +{ + Q_D(const QWebEngineDownloadRequest); + return d->receivedBytes; +} + +/*! + Returns the download's origin URL. +*/ + +QUrl QWebEngineDownloadRequest::url() const +{ + Q_D(const QWebEngineDownloadRequest); + return d->downloadUrl; +} + +/*! + Returns the MIME type of the download. +*/ + +QString QWebEngineDownloadRequest::mimeType() const +{ + Q_D(const QWebEngineDownloadRequest); + return d->mimeType; +} + +/*! + Returns the download directory path. +*/ + +QString QWebEngineDownloadRequest::downloadDirectory() const +{ + Q_D(const QWebEngineDownloadRequest); + return d->downloadDirectory; +} + +/*! + Sets \a directory as the directory path to download the file to. + + The download directory path can only be set in response to the QWebEngineProfile::downloadRequested() + signal before the download is accepted. Past that point, this function has no effect on the + download item's state. +*/ + +void QWebEngineDownloadRequest::setDownloadDirectory(const QString &directory) +{ + Q_D(QWebEngineDownloadRequest); + if (d->downloadState != QWebEngineDownloadRequest::DownloadRequested) { + qWarning("Setting the download directory is not allowed after the download has been accepted."); + return; + } + + if (!directory.isEmpty() && d->downloadDirectory != directory) + d->downloadDirectory = directory; + + if (!d->isCustomFileName && d->m_profileAdapter) + d->downloadFileName = QFileInfo(d->m_profileAdapter->determineDownloadPath(d->downloadDirectory, + d->suggestedFileName, + d->startTime)).fileName(); +} + +/*! + Returns the file name to download the file to. +*/ + +QString QWebEngineDownloadRequest::downloadFileName() const +{ + Q_D(const QWebEngineDownloadRequest); + return d->downloadFileName; +} + +/*! + Sets \a fileName as the file name to download the file to. + + The download file name can only be set in response to the QWebEngineProfile::downloadRequested() + signal before the download is accepted. Past that point, this function has no effect on the + download item's state. +*/ + +void QWebEngineDownloadRequest::setDownloadFileName(const QString &fileName) +{ + Q_D(QWebEngineDownloadRequest); + if (d->downloadState != QWebEngineDownloadRequest::DownloadRequested) { + qWarning("Setting the download file name is not allowed after the download has been accepted."); + return; + } + + if (!fileName.isEmpty()) { + d->downloadFileName = fileName; + d->isCustomFileName = true; + } +} + +/*! + Returns the suggested file name. +*/ + +QString QWebEngineDownloadRequest::suggestedFileName() const +{ + Q_D(const QWebEngineDownloadRequest); + return d->suggestedFileName; +} + +/*! + Returns whether this download is finished (completed, cancelled, or non-resumable interrupted state). + + \sa finished(), state(), +*/ + +bool QWebEngineDownloadRequest::isFinished() const +{ + Q_D(const QWebEngineDownloadRequest); + return d->downloadFinished; +} + +/*! + Returns whether this download is paused. + + \sa pause(), resume() +*/ + +bool QWebEngineDownloadRequest::isPaused() const +{ + Q_D(const QWebEngineDownloadRequest); + return d->downloadPaused; +} + +/*! + Returns the format the web page will be saved in if this is a download request for a web page. + \sa setSavePageFormat(), isSavePageDownload() +*/ +QWebEngineDownloadRequest::SavePageFormat QWebEngineDownloadRequest::savePageFormat() const +{ + Q_D(const QWebEngineDownloadRequest); + return d->savePageFormat; +} + +/*! + Sets the \a format the web page will be saved in if this is a download request for a web page. + + \sa savePageFormat(), isSavePageDownload() +*/ +void QWebEngineDownloadRequest::setSavePageFormat(QWebEngineDownloadRequest::SavePageFormat format) +{ + Q_D(QWebEngineDownloadRequest); + if (d->savePageFormat != format) { + d->savePageFormat = format; + Q_EMIT savePageFormatChanged(); + } +} + +/*! + Returns \c true if this is a download request for saving a web page. + + \sa savePageFormat(), setSavePageFormat() + */ +bool QWebEngineDownloadRequest::isSavePageDownload() const +{ + Q_D(const QWebEngineDownloadRequest); + return d->isSavePageDownload; +} + +/*! + Returns the reason why the download was interrupted. + + \sa interruptReasonString() +*/ + +QWebEngineDownloadRequest::DownloadInterruptReason QWebEngineDownloadRequest::interruptReason() const +{ + Q_D(const QWebEngineDownloadRequest); + return d->interruptReason; +} + +/*! + Returns a human-readable description of the reason for interrupting the download. + + \sa interruptReason() +*/ + +QString QWebEngineDownloadRequest::interruptReasonString() const +{ + return ProfileAdapterClient::downloadInterruptReasonToString( + static_cast<ProfileAdapterClient::DownloadInterruptReason>(interruptReason())); +} + +/*! + Returns the page the download was requested on. If the download was not triggered by content in a page, + \c nullptr is returned. +*/ +QObject *QWebEngineDownloadRequest::page() const +{ + Q_D(const QWebEngineDownloadRequest); + return d->page; +} + +QWebEngineDownloadRequest::QWebEngineDownloadRequest(QWebEngineDownloadRequestPrivate *p, QObject *parent) + : QObject(parent) + , d_ptr(p) +{ + p->q_ptr = this; +} + +/*! \internal +*/ +QWebEngineDownloadRequest::~QWebEngineDownloadRequest() +{ + // MEMO Items are owned by profile by default and will be destroyed on profile's destruction + // It's not safe to access profile in that case, so we rely on profile to clean up items + if (!isFinished()) + cancel(); +} + +QT_END_NAMESPACE diff --git a/src/core/api/qwebenginedownloadrequest.h b/src/core/api/qwebenginedownloadrequest.h new file mode 100644 index 000000000..38d43cf1f --- /dev/null +++ b/src/core/api/qwebenginedownloadrequest.h @@ -0,0 +1,178 @@ +/**************************************************************************** +** +** Copyright (C) 2020 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 QWEBENGINEDOWNLOADREQUEST_H +#define QWEBENGINEDOWNLOADREQUEST_H + +#include <QtWebEngineCore/qtwebenginecoreglobal.h> + +#include <QtCore/qobject.h> +#include <QtCore/QUrl> + +QT_BEGIN_NAMESPACE + +//TODO: class QWebEnginePage; +class QWebEngineDownloadRequestPrivate; +class QWebEngineProfilePrivate; + +class Q_WEBENGINECORE_EXPORT QWebEngineDownloadRequest : public QObject +{ + Q_OBJECT +public: + Q_PROPERTY(quint32 id READ id CONSTANT FINAL) + Q_PROPERTY(DownloadState state READ state NOTIFY stateChanged FINAL) + Q_PROPERTY(SavePageFormat savePageFormat READ savePageFormat WRITE setSavePageFormat NOTIFY savePageFormatChanged FINAL) + Q_PROPERTY(qint64 totalBytes READ totalBytes NOTIFY totalBytesChanged FINAL) + Q_PROPERTY(qint64 receivedBytes READ receivedBytes NOTIFY receivedBytesChanged FINAL) + Q_PROPERTY(QString mimeType READ mimeType FINAL) + Q_PROPERTY(DownloadInterruptReason interruptReason READ interruptReason NOTIFY interruptReasonChanged FINAL) + Q_PROPERTY(QString interruptReasonString READ interruptReasonString NOTIFY interruptReasonChanged FINAL) + Q_PROPERTY(bool isFinished READ isFinished NOTIFY isFinishedChanged FINAL) + Q_PROPERTY(bool isPaused READ isPaused NOTIFY isPausedChanged FINAL) + Q_PROPERTY(bool isSavePageDownload READ isSavePageDownload CONSTANT FINAL) + //TODO: Q_PROPERTY(QQuickWebEngineView *view READ view CONSTANT REVISION 7 FINAL) + Q_PROPERTY(QUrl url READ url CONSTANT FINAL) + Q_PROPERTY(QString suggestedFileName READ suggestedFileName CONSTANT FINAL) + Q_PROPERTY(QString downloadDirectory READ downloadDirectory WRITE setDownloadDirectory NOTIFY downloadDirectoryChanged FINAL) + Q_PROPERTY(QString downloadFileName READ downloadFileName WRITE setDownloadFileName NOTIFY downloadFileNameChanged FINAL) + + ~QWebEngineDownloadRequest(); + + enum DownloadState { + DownloadRequested, + DownloadInProgress, + DownloadCompleted, + DownloadCancelled, + DownloadInterrupted + }; + Q_ENUM(DownloadState) + + enum SavePageFormat { + UnknownSaveFormat = -1, + SingleHtmlSaveFormat, + CompleteHtmlSaveFormat, + MimeHtmlSaveFormat + }; + Q_ENUM(SavePageFormat) + + enum DownloadInterruptReason { + NoReason = 0, + FileFailed = 1, + FileAccessDenied = 2, + FileNoSpace = 3, + FileNameTooLong = 5, + FileTooLarge = 6, + FileVirusInfected = 7, + FileTransientError = 10, + FileBlocked = 11, + FileSecurityCheckFailed = 12, + FileTooShort = 13, + FileHashMismatch = 14, + NetworkFailed = 20, + NetworkTimeout = 21, + NetworkDisconnected = 22, + NetworkServerDown = 23, + NetworkInvalidRequest = 24, + ServerFailed = 30, + //ServerNoRange = 31, + ServerBadContent = 33, + ServerUnauthorized = 34, + ServerCertProblem = 35, + ServerForbidden = 36, + ServerUnreachable = 37, + UserCanceled = 40, + //UserShutdown = 41, + //Crash = 50 + }; + Q_ENUM(DownloadInterruptReason) + + quint32 id() const; + DownloadState state() const; + qint64 totalBytes() const; + qint64 receivedBytes() const; + QUrl url() const; + QString mimeType() const; + bool isFinished() const; + bool isPaused() const; + SavePageFormat savePageFormat() const; + void setSavePageFormat(SavePageFormat format); + DownloadInterruptReason interruptReason() const; + QString interruptReasonString() const; + bool isSavePageDownload() const; + QString suggestedFileName() const; + QString downloadDirectory() const; + void setDownloadDirectory(const QString &directory); + QString downloadFileName() const; + void setDownloadFileName(const QString &fileName); + + //TODO: + QObject *page() const; + +public Q_SLOTS: + void accept(); + void cancel(); + void pause(); + void resume(); + +Q_SIGNALS: + void stateChanged(QWebEngineDownloadRequest::DownloadState state); + //TODO: fix it for qml + void downloadProgress(qint64 bytesReceived, qint64 bytesTotal); + void savePageFormatChanged(); + void receivedBytesChanged(); + void totalBytesChanged(); + void interruptReasonChanged(); + void isFinishedChanged(); + void isPausedChanged(); + void downloadDirectoryChanged(); + void downloadFileNameChanged(); + +private: + Q_DISABLE_COPY(QWebEngineDownloadRequest) + Q_DECLARE_PRIVATE(QWebEngineDownloadRequest) + + friend class QWebEngineProfilePrivate; + friend class QQuickWebEngineProfilePrivate; + QWebEngineDownloadRequest(QWebEngineDownloadRequestPrivate*, QObject *parent = Q_NULLPTR); + QScopedPointer<QWebEngineDownloadRequestPrivate> d_ptr; +}; + +QT_END_NAMESPACE + +#endif // QWEBENGINEDOWNLOADREQUEST_H diff --git a/src/core/api/qwebenginedownloadrequest_p.h b/src/core/api/qwebenginedownloadrequest_p.h new file mode 100644 index 000000000..bc172bd7b --- /dev/null +++ b/src/core/api/qwebenginedownloadrequest_p.h @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QWEBENGINEDOWNLOADREQUEST_P_H +#define QWEBENGINEDOWNLOADREQUEST_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 "qtwebenginecoreglobal.h" +#include "qwebenginedownloadrequest.h" +#include "profile_adapter_client.h" +#include <QString> +#include <QPointer> + +namespace QtWebEngineCore { +class ProfileAdapter; +} + +QT_BEGIN_NAMESPACE + +class Q_WEBENGINECORE_PRIVATE_EXPORT QWebEngineDownloadRequestPrivate { +public: + QWebEngineDownloadRequestPrivate(QtWebEngineCore::ProfileAdapter *adapter, const QUrl &url); + ~QWebEngineDownloadRequestPrivate(); + + void update(const QtWebEngineCore::ProfileAdapterClient::DownloadItemInfo &info); + void setFinished(); + + bool downloadFinished; + quint32 downloadId; + qint64 startTime; + QWebEngineDownloadRequest::DownloadState downloadState; + QWebEngineDownloadRequest::SavePageFormat savePageFormat; + QWebEngineDownloadRequest::DownloadInterruptReason interruptReason; + QString downloadPath; + const QUrl downloadUrl; + QString mimeType; + bool downloadPaused; + QString suggestedFileName; + QString downloadDirectory; + QString downloadFileName; + bool isCustomFileName; + qint64 totalBytes; + qint64 receivedBytes; + bool isSavePageDownload; + QWebEngineDownloadRequest *q_ptr; + QPointer<QtWebEngineCore::ProfileAdapter> m_profileAdapter; + QObject *page; + Q_DECLARE_PUBLIC(QWebEngineDownloadRequest) +}; + +QT_END_NAMESPACE + +#endif // QWEBENGINEDOWNLOADREQUEST_P_H + diff --git a/src/core/api/qwebenginefullscreenrequest.cpp b/src/core/api/qwebenginefullscreenrequest.cpp new file mode 100644 index 000000000..facc8910d --- /dev/null +++ b/src/core/api/qwebenginefullscreenrequest.cpp @@ -0,0 +1,147 @@ +/**************************************************************************** +** +** 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 "qwebenginefullscreenrequest.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QWebEngineFullScreenRequest + \brief The QWebEngineFullScreenRequest class enables accepting or rejecting + requests for entering and exiting the fullscreen mode. + + \since 5.6 + + \inmodule QtWebEngineCore + + To allow elements such as videos to be shown in the fullscreen mode, + applications must set QWebEngineSettings::FullScreenSupportEnabled and + connect to QWebEnginePage::fullScreenRequested, which takes a + QWebEngineFullScreenRequest instance as an argument. + + If an element of a web page requests to be shown in the fullscreen mode, + QWebEnginePage::fullScreenRequested will be emitted with an + QWebEngineFullScreenRequest instance as an argument where toggleOn() returns + \c true. The signal handler needs to then either call accept() or reject(). + + If the request to enter the fullscreen mode is accepted, the element + requesting fullscreen mode will fill the viewport, but it is up to the + application to make the view fullscreen or to move the page to a view that + is in the fullscreen mode. + + Likewise, a QWebEnginePage::fullScreenRequested will be emitted when + the user wants to leave the full screen mode (that is, through the + QWebEnginePage::ExitFullScreen context menu action). In this case, + toggleOn() will return \c false, and the signal handler again needs to + accept() or reject() the request. If it is accepted, the applicaton needs to + make sure that the global window state is restored. +*/ + +/*! + \property QWebEngineFullScreenRequest::toggleOn + \brief Whether the web page has issued a request to enter fullscreen mode. +*/ + +/*! + \property QWebEngineFullScreenRequest::origin + \brief The URL to be opened in the fullscreen mode. +*/ + +/*! + Creates a request for opening the \a page from the URL specified by + \a origin in the fullscreen mode if \a fullscreen is \c true. +*/ + +class QWebEngineFullScreenRequestPrivate : public QSharedData { +public: + QWebEngineFullScreenRequestPrivate(const QUrl &origin, bool toggleOn, const std::function<void (bool)> &setFullScreenCallback) + : m_origin(origin) + , m_toggleOn(toggleOn) + , m_setFullScreenCallback(setFullScreenCallback) { } + + const QUrl m_origin; + const bool m_toggleOn; + const std::function<void (bool)> m_setFullScreenCallback; +}; + +QWebEngineFullScreenRequest::QWebEngineFullScreenRequest(const QUrl &origin, bool toggleOn, const std::function<void (bool)> &setFullScreenCallback) + : d_ptr(new QWebEngineFullScreenRequestPrivate(origin, toggleOn, setFullScreenCallback)) { } + +QWebEngineFullScreenRequest::QWebEngineFullScreenRequest(const QWebEngineFullScreenRequest &other) = default; +QWebEngineFullScreenRequest& QWebEngineFullScreenRequest::operator=(const QWebEngineFullScreenRequest &other) = default; +QWebEngineFullScreenRequest::QWebEngineFullScreenRequest(QWebEngineFullScreenRequest &&other) = default; +QWebEngineFullScreenRequest& QWebEngineFullScreenRequest::operator=(QWebEngineFullScreenRequest &&other) = default; +QWebEngineFullScreenRequest::~QWebEngineFullScreenRequest() = default; + +/*! + Rejects a request to enter or exit the fullscreen mode. +*/ +void QWebEngineFullScreenRequest::reject() +{ + d_ptr->m_setFullScreenCallback(!d_ptr->m_toggleOn); +} + +/*! + Accepts the request to enter or exit the fullscreen mode. +*/ +void QWebEngineFullScreenRequest::accept() +{ + d_ptr->m_setFullScreenCallback(d_ptr->m_toggleOn); +} + +/*! + \fn QWebEngineFullScreenRequest::toggleOn() const + Returns \c true if the web page has issued a request to enter the fullscreen + mode, otherwise returns \c false. +*/ +bool QWebEngineFullScreenRequest::toggleOn() const +{ + return d_ptr->m_toggleOn; +} + +/*! + \fn QWebEngineFullScreenRequest::origin() const + Returns the URL to be opened in the fullscreen mode. +*/ +QUrl QWebEngineFullScreenRequest::origin() const +{ + return d_ptr->m_origin; +} + +QT_END_NAMESPACE diff --git a/src/core/compositor/display_frame_sink.h b/src/core/api/qwebenginefullscreenrequest.h index f620dc4f2..95911ed0a 100644 --- a/src/core/compositor/display_frame_sink.h +++ b/src/core/api/qwebenginefullscreenrequest.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2019 The Qt Company Ltd. +** 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. @@ -37,41 +37,46 @@ ** ****************************************************************************/ -#ifndef DISPLAY_FRAME_SINK_H -#define DISPLAY_FRAME_SINK_H +#ifndef QWEBENGINEFULLSCREENREQUEST_H +#define QWEBENGINEFULLSCREENREQUEST_H -#include "display_consumer.h" -#include "display_producer.h" +#include <QtWebEngineCore/qtwebenginecoreglobal.h> -#include "base/memory/ref_counted.h" -#include "base/memory/scoped_refptr.h" -#include "components/viz/common/surfaces/frame_sink_id.h" +#include <QtCore/qglobal.h> +#include <QtCore/qshareddata.h> +#include <QtCore/qurl.h> -#include <QMutex> +#include <functional> -namespace QtWebEngineCore { +QT_BEGIN_NAMESPACE -// Connects a DisplayConsumer with a DisplayProducer. -class DisplayFrameSink final : public base::RefCountedThreadSafe<DisplayFrameSink> +class QWebEngineFullScreenRequestPrivate; + +class Q_WEBENGINECORE_EXPORT QWebEngineFullScreenRequest { + Q_GADGET + Q_PROPERTY(bool toggleOn READ toggleOn CONSTANT) + Q_PROPERTY(QUrl origin READ origin CONSTANT) + public: - static scoped_refptr<DisplayFrameSink> findOrCreate(viz::FrameSinkId frameSinkId); - DisplayFrameSink(viz::FrameSinkId frameSinkId); - ~DisplayFrameSink(); - void connect(DisplayConsumer *consumer); - void connect(DisplayProducer *producer); - void disconnect(DisplayConsumer *consumer); - void disconnect(DisplayProducer *producer); - void scheduleUpdate(); - QSGNode *updatePaintNode(QSGNode *oldNode, RenderWidgetHostViewQtDelegate *delegate); + QWebEngineFullScreenRequest(const QWebEngineFullScreenRequest &other); + QWebEngineFullScreenRequest &operator=(const QWebEngineFullScreenRequest &other); + QWebEngineFullScreenRequest(QWebEngineFullScreenRequest &&other); + QWebEngineFullScreenRequest &operator=(QWebEngineFullScreenRequest &&other); + ~QWebEngineFullScreenRequest(); + + Q_INVOKABLE void reject(); + Q_INVOKABLE void accept(); + bool toggleOn() const; + QUrl origin() const; private: - const viz::FrameSinkId m_frameSinkId; - mutable QMutex m_mutex; - DisplayProducer *m_producer = nullptr; - DisplayConsumer *m_consumer = nullptr; + friend class QWebEnginePagePrivate; + friend class QQuickWebEngineViewPrivate; + QWebEngineFullScreenRequest(const QUrl &origin, bool toggleOn, const std::function<void (bool)> &setFullScreenCallback); + QExplicitlySharedDataPointer<QWebEngineFullScreenRequestPrivate> d_ptr; }; -} // namespace QtWebEngineCore +QT_END_NAMESPACE -#endif // !DISPLAY_FRAME_SINK_H +#endif diff --git a/src/core/api/qwebenginehttprequest.cpp b/src/core/api/qwebenginehttprequest.cpp index 3395cc99f..f5733cde4 100644 --- a/src/core/api/qwebenginehttprequest.cpp +++ b/src/core/api/qwebenginehttprequest.cpp @@ -72,7 +72,7 @@ public: QUrl url; QWebEngineHttpRequest::Method method; typedef QPair<QByteArray, QByteArray> HeaderPair; - typedef QVector<HeaderPair> Headers; + typedef QList<HeaderPair> Headers; Headers headers; QByteArray postData; @@ -96,7 +96,7 @@ public: Headers::ConstIterator findHeader(const QByteArray &key) const; Headers allHeaders() const; - QVector<QByteArray> headersKeys() const; + QList<QByteArray> headersKeys() const; void setHeader(const QByteArray &key, const QByteArray &value); void unsetHeader(const QByteArray &key); void setAllHeaders(const Headers &list); @@ -293,7 +293,7 @@ QByteArray QWebEngineHttpRequest::header(const QByteArray &headerName) const \sa setHeader(), header(), hasHeader(), unsetHeader() */ -QVector<QByteArray> QWebEngineHttpRequest::headers() const +QList<QByteArray> QWebEngineHttpRequest::headers() const { return d->headersKeys(); } @@ -339,9 +339,9 @@ QWebEngineHttpRequestPrivate::Headers QWebEngineHttpRequestPrivate::allHeaders() return headers; } -QVector<QByteArray> QWebEngineHttpRequestPrivate::headersKeys() const +QList<QByteArray> QWebEngineHttpRequestPrivate::headersKeys() const { - QVector<QByteArray> result; + QList<QByteArray> result; result.reserve(headers.size()); Headers::ConstIterator it = headers.constBegin(), end = headers.constEnd(); for (; it != end; ++it) diff --git a/src/core/api/qwebenginehttprequest.h b/src/core/api/qwebenginehttprequest.h index 1c4d7837b..ce77c04dd 100644 --- a/src/core/api/qwebenginehttprequest.h +++ b/src/core/api/qwebenginehttprequest.h @@ -41,9 +41,9 @@ #define QWEBENGINEHTTPREQUEST_H #include <QtWebEngineCore/qtwebenginecoreglobal.h> -#include <QtCore/qshareddata.h> -#include <QtCore/qvector.h> +#include <QtCore/qlist.h> #include <QtCore/qmap.h> +#include <QtCore/qshareddata.h> #include <QtCore/qstring.h> #include <QtCore/qurl.h> @@ -87,7 +87,7 @@ public: void setPostData(const QByteArray &postData); bool hasHeader(const QByteArray &headerName) const; - QVector<QByteArray> headers() const; + QList<QByteArray> headers() const; QByteArray header(const QByteArray &headerName) const; void setHeader(const QByteArray &headerName, const QByteArray &value); void unsetHeader(const QByteArray &headerName); diff --git a/src/core/api/qwebenginescript.cpp b/src/core/api/qwebenginescript.cpp new file mode 100644 index 000000000..650ad5c53 --- /dev/null +++ b/src/core/api/qwebenginescript.cpp @@ -0,0 +1,318 @@ +/**************************************************************************** +** +** 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 "qwebenginescript.h" + +#include "user_script.h" +#include <QtCore/QDebug> +#include <QtCore/QFile> + +using QtWebEngineCore::UserScript; + +QT_BEGIN_NAMESPACE + +/*! + \class QWebEngineScript + \inmodule QtWebEngineCore + \since 5.5 + \brief The QWebEngineScript class encapsulates a JavaScript program. + + + QWebEngineScript enables the programmatic injection of so called \e {user scripts} in the + JavaScript engine at different points, determined by injectionPoint(), during the loading of web + contents. + + Scripts can be executed either in the main JavaScript \e world, along with the rest of the + JavaScript coming from the web contents, or in their own isolated world. While the DOM of the + page can be accessed from any world, JavaScript variables of a function defined in one world are + not accessible from a different one. ScriptWorldId provides some predefined IDs for this + purpose. + + The following \l Greasemonkey attributes are supported since Qt 5.8: + \c @exclude, \c @include, \c @name, \c @match, and \c @run-at. + + Use QWebEnginePage::scripts() and QWebEngineProfile::scripts() to access + the collection of scripts associated with a single page or a + number of pages sharing the same profile. + + \sa {Script Injection} +*/ +/*! + \enum QWebEngineScript::InjectionPoint + + This enum describes the timing of the script injection: + + \value DocumentCreation The script will be executed as soon as the document is created. This is not suitable for + any DOM operation. + \value DocumentReady The script will run as soon as the DOM is ready. This is equivalent to the + \c DOMContentLoaded event firing in JavaScript. + \value Deferred The script will run when the page load finishes, or 500ms after the document is ready, whichever + comes first. + +*/ +/*! + \enum QWebEngineScript::ScriptWorldId + + This enum provides pre-defined world IDs for isolating user scripts into different worlds: + + \value MainWorld The world used by the page's web contents. It can be useful in order to expose custom functionality + to web contents in certain scenarios. + \value ApplicationWorld The default isolated world used for application level functionality implemented in JavaScript. + \value UserWorld The first isolated world to be used by scripts set by users if the application is not making use + of more worlds. As a rule of thumb, if that functionality is exposed to the application users, each individual script + should probably get its own isolated world. + +*/ + +/*! + \fn QWebEngineScript::operator!=(const QWebEngineScript &other) const + + Returns \c true if the script is not equal to \a other, otherwise returns \c false. +*/ + +/*! + \fn QWebEngineScript::swap(QWebEngineScript &other) + + Swaps the contents of the script with the contents of \a other. +*/ + +/*! + * Constructs a null script. + */ + +QWebEngineScript::QWebEngineScript() + : d(new UserScript) +{ +} + +/*! + * Constructs a user script using the contents of \a other. + */ +QWebEngineScript::QWebEngineScript(const QWebEngineScript &other) + : d(other.d) +{ +} + +/*! + Destroys a script. +*/ +QWebEngineScript::~QWebEngineScript() +{ +} + +/*! + Assigns \a other to the script. +*/ +QWebEngineScript &QWebEngineScript::operator=(const QWebEngineScript &other) +{ + d = other.d; + return *this; +} + +/*! + * Returns the name of the script. Can be useful to retrieve a particular script from a + * QWebEngineScriptCollection. + * + * \sa QWebEngineScriptCollection::findScript(), QWebEngineScriptCollection::findScripts() + */ + +QString QWebEngineScript::name() const +{ + return d->name(); +} + +/*! + * Sets the script name to \a scriptName. + */ +void QWebEngineScript::setName(const QString &scriptName) +{ + if (scriptName == name()) + return; + d->setName(scriptName); +} + + +QUrl QWebEngineScript::sourceUrl() const +{ + return d->sourceUrl(); +} + +void QWebEngineScript::setSourceUrl(const QUrl &url) +{ + if (url == sourceUrl()) + return; + + d->setSourceUrl(url); + + QFile file; + if (url.scheme().compare(QLatin1String("qrc"), Qt::CaseInsensitive) == 0) { + if (url.authority().isEmpty()) + file.setFileName(QLatin1Char(':') + url.path()); + return; + } else { + file.setFileName(url.toLocalFile()); + } + + if (!file.open(QIODevice::ReadOnly)) { + qWarning() << "Can't open user script " << url; + return; + } + + QString source = QString::fromUtf8(file.readAll()); + setSourceCode(source); +} + +/*! + Returns the source of the script. + */ +QString QWebEngineScript::sourceCode() const +{ + return d->sourceCode(); +} + +/*! + * Sets the script source to \a scriptSource. + */ +void QWebEngineScript::setSourceCode(const QString &scriptSource) +{ + if (scriptSource == sourceCode()) + return; + d->setSourceCode(scriptSource); +} + +ASSERT_ENUMS_MATCH(QWebEngineScript::Deferred, UserScript::AfterLoad) +ASSERT_ENUMS_MATCH(QWebEngineScript::DocumentReady, UserScript::DocumentLoadFinished) +ASSERT_ENUMS_MATCH(QWebEngineScript::DocumentCreation, UserScript::DocumentElementCreation) + +/*! + * Returns the point in the loading process at which the script will be executed. + * The default value is QWebEngineScript::Deferred. + * + * \sa setInjectionPoint() + */ +QWebEngineScript::InjectionPoint QWebEngineScript::injectionPoint() const +{ + return static_cast<QWebEngineScript::InjectionPoint>(d->injectionPoint()); +} +/*! + * Sets the point at which to execute the script to be \a p. + * + * \sa InjectionPoint + */ +void QWebEngineScript::setInjectionPoint(QWebEngineScript::InjectionPoint p) +{ + if (p == injectionPoint()) + return; + d->setInjectionPoint(static_cast<UserScript::InjectionPoint>(p)); +} + +/*! + Returns the world ID defining which world the script is executed in. + */ +quint32 QWebEngineScript::worldId() const +{ + return d->worldId(); +} + +/*! + Sets the world ID of the isolated world to \a id when running this script. + + Must be between \c 0 and \c 256. + */ +void QWebEngineScript::setWorldId(quint32 id) +{ + if (id == d->worldId()) + return; + d->setWorldId(id); +} + +/*! + Returns \c true if the script is executed on every frame in the page, or \c false if it is only + ran for the main frame. + */ +bool QWebEngineScript::runsOnSubFrames() const +{ + return d->runsOnSubFrames(); +} + +/*! + * Executes the script on sub frames in addition to the main frame if \a on returns \c true. + */ +void QWebEngineScript::setRunsOnSubFrames(bool on) +{ + if (runsOnSubFrames() == on) + return; + d->setRunsOnSubFrames(on); +} + +/*! + Returns \c true if the script is equal to \a other, otherwise returns \c false. + */ +bool QWebEngineScript::operator==(const QWebEngineScript &other) const +{ + return d == other.d || *d == *(other.d); +} + +QWebEngineScript::QWebEngineScript(const UserScript &coreScript) + : d(new UserScript(coreScript)) +{ +} + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug d, const QWebEngineScript &script) +{ + d.nospace() << "QWebEngineScript(" << script.name() << ", "; + switch (script.injectionPoint()) { + case QWebEngineScript::DocumentCreation: + d << "QWebEngineScript::DocumentCreation" << ", "; + break; + case QWebEngineScript::DocumentReady: + d << "QWebEngineScript::DocumentReady" << ", "; + break; + case QWebEngineScript::Deferred: + d << "QWebEngineScript::Deferred" << ", "; + break; + } + d << script.worldId() << ", " + << script.runsOnSubFrames() << ", " << script.sourceCode() << ")"; + return d.space(); +} +#endif + +QT_END_NAMESPACE diff --git a/src/core/api/qwebenginescript.h b/src/core/api/qwebenginescript.h new file mode 100644 index 000000000..0c1849dac --- /dev/null +++ b/src/core/api/qwebenginescript.h @@ -0,0 +1,128 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QWEBENGINESCRIPT_H +#define QWEBENGINESCRIPT_H + +#include <QtWebEngineCore/qtwebenginecoreglobal.h> +#include <QtCore/QUrl> +#include <QtCore/QObject> +#include <QtCore/QSharedDataPointer> + +namespace QtWebEngineCore { +class UserScript; +} // namespace + +QT_BEGIN_NAMESPACE + +class Q_WEBENGINECORE_EXPORT QWebEngineScript { + + Q_GADGET + Q_PROPERTY(QString name READ name WRITE setName FINAL) + Q_PROPERTY(QUrl sourceUrl READ sourceUrl WRITE setSourceUrl FINAL) + Q_PROPERTY(QString sourceCode READ sourceCode WRITE setSourceCode FINAL) + Q_PROPERTY(InjectionPoint injectionPoint READ injectionPoint WRITE setInjectionPoint FINAL) + Q_PROPERTY(quint32 worldId READ worldId WRITE setWorldId FINAL) + Q_PROPERTY(bool runsOnSubFrames READ runsOnSubFrames WRITE setRunsOnSubFrames FINAL) + +public: + + enum InjectionPoint { + Deferred, + DocumentReady, + DocumentCreation + }; + + Q_ENUM(InjectionPoint) + + enum ScriptWorldId { + MainWorld = 0, + ApplicationWorld, + UserWorld + }; + + Q_ENUM(ScriptWorldId) + + QWebEngineScript(); + QWebEngineScript(const QWebEngineScript &other); + ~QWebEngineScript(); + + QWebEngineScript &operator=(const QWebEngineScript &other); + + QString name() const; + void setName(const QString &); + + QUrl sourceUrl() const; + void setSourceUrl(const QUrl &url); + + QString sourceCode() const; + void setSourceCode(const QString &); + + InjectionPoint injectionPoint() const; + void setInjectionPoint(InjectionPoint); + + quint32 worldId() const; + void setWorldId(quint32); + + bool runsOnSubFrames() const; + void setRunsOnSubFrames(bool on); + + bool operator==(const QWebEngineScript &other) const; + inline bool operator!=(const QWebEngineScript &other) const + { return !operator==(other); } + void swap(QWebEngineScript &other) { qSwap(d, other.d); } + +private: + friend class QQuickWebEngineScriptCollectionPrivate; + friend class QWebEngineScriptCollectionPrivate; + friend class QWebEngineScriptCollection; + QWebEngineScript(const QtWebEngineCore::UserScript &); + + QSharedDataPointer<QtWebEngineCore::UserScript> d; +}; + +Q_DECLARE_TYPEINFO(QWebEngineScript, Q_MOVABLE_TYPE); + +#ifndef QT_NO_DEBUG_STREAM +Q_WEBENGINECORE_EXPORT QDebug operator<<(QDebug, const QWebEngineScript &); +#endif + +QT_END_NAMESPACE + +#endif // QWEBENGINESCRIPT_H diff --git a/src/core/api/qwebenginescriptcollection.cpp b/src/core/api/qwebenginescriptcollection.cpp new file mode 100644 index 000000000..6dfa12c46 --- /dev/null +++ b/src/core/api/qwebenginescriptcollection.cpp @@ -0,0 +1,223 @@ +/**************************************************************************** +** +** 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 "qwebenginescriptcollection.h" +#include "qwebenginescriptcollection_p.h" + +#include "renderer_host/user_resource_controller_host.h" + +using QtWebEngineCore::UserScript; + +/*! + \class QWebEngineScriptCollection + \inmodule QtWebEngineCore + \since 5.5 + \brief The QWebEngineScriptCollection class represents a collection of user scripts. + + QWebEngineScriptCollection manages a set of user scripts. + + Use QWebEnginePage::scripts() and QWebEngineProfile::scripts() to access + the collection of scripts associated with a single page or a + number of pages sharing the same profile. + + \sa {Script Injection} +*/ + +/*! + \fn QWebEngineScriptCollection::isEmpty() const + + Returns \c true if the collection is empty; otherwise returns \c false. +*/ + +/*! + \fn QWebEngineScriptCollection::size() const + + Returns the number of elements in the collection. +*/ + +QWebEngineScriptCollection::QWebEngineScriptCollection(QWebEngineScriptCollectionPrivate *collectionPrivate) + :d(collectionPrivate) +{ +} + +/*! + Destroys the collection. +*/ +QWebEngineScriptCollection::~QWebEngineScriptCollection() +{ +} + +/*! + Returns the number of elements in the collection. + */ + +int QWebEngineScriptCollection::count() const +{ + return d->count(); +} + +/*! + Returns \c true if the collection contains an occurrence of \a value; otherwise returns + \c false. + */ + +bool QWebEngineScriptCollection::contains(const QWebEngineScript &value) const +{ + return d->contains(value); +} + +/*! + Returns the list of scripts in the collection with the name \a name, or an empty list if none + was found. + */ + +QList<QWebEngineScript> QWebEngineScriptCollection::find(const QString &name) const +{ + return d->toList(name); +} +/*! + Inserts the script \a s into the collection. + */ +void QWebEngineScriptCollection::insert(const QWebEngineScript &s) +{ + d->insert(s); +} +/*! + Inserts scripts from the list \a list into the collection. + */ +void QWebEngineScriptCollection::insert(const QList<QWebEngineScript> &list) +{ + d->reserve(list.size()); + for (const QWebEngineScript &s : list) + d->insert(s); +} + +/*! + Removes \a script from the collection. + + Returns \c true if the script was found and successfully removed from the collection; otherwise + returns \c false. + */ +bool QWebEngineScriptCollection::remove(const QWebEngineScript &script) +{ + return d->remove(script); +} + +/*! + * Removes all scripts from this collection. + */ +void QWebEngineScriptCollection::clear() +{ + d->clear(); +} + +/*! + Returns a list with the values of the scripts used in this collection. + */ +QList<QWebEngineScript> QWebEngineScriptCollection::toList() const +{ + return d->toList(); +} + + +QWebEngineScriptCollectionPrivate::QWebEngineScriptCollectionPrivate(QtWebEngineCore::UserResourceControllerHost *controller, QSharedPointer<QtWebEngineCore::WebContentsAdapter> webContents) + : m_scriptController(controller) + , m_contents(webContents) +{ +} + +int QWebEngineScriptCollectionPrivate::count() const +{ + return m_scripts.count(); +} + +bool QWebEngineScriptCollectionPrivate::contains(const QWebEngineScript &s) const +{ + return m_scripts.contains(s); +} + +void QWebEngineScriptCollectionPrivate::insert(const QWebEngineScript &script) +{ + m_scripts.append(script); + if (!m_contents || m_contents->isInitialized()) + m_scriptController->addUserScript(*script.d, m_contents.data()); +} + +bool QWebEngineScriptCollectionPrivate::remove(const QWebEngineScript &script) +{ + if (!m_contents || m_contents->isInitialized()) + m_scriptController->removeUserScript(*script.d, m_contents.data()); + return m_scripts.removeAll(script); +} + +QList<QWebEngineScript> QWebEngineScriptCollectionPrivate::toList(const QString &scriptName) const +{ + if (scriptName.isNull()) + return m_scripts; + + QList<QWebEngineScript> ret; + for (const QWebEngineScript &script : qAsConst(m_scripts)) + if (scriptName == script.name()) + ret.append(script); + return ret; +} + +void QWebEngineScriptCollectionPrivate::clear() +{ + m_scripts.clear(); + if (!m_contents || m_contents->isInitialized()) + m_scriptController->clearAllScripts(m_contents.data()); +} + +void QWebEngineScriptCollectionPrivate::reserve(int capacity) +{ + m_scripts.reserve(capacity); + if (!m_contents || m_contents->isInitialized()) + m_scriptController->reserve(m_contents.data(), capacity); +} + +void QWebEngineScriptCollectionPrivate::initializationFinished(QSharedPointer<QtWebEngineCore::WebContentsAdapter> contents) +{ + Q_ASSERT(m_contents); + Q_ASSERT(contents); + + for (const QWebEngineScript &script : qAsConst(m_scripts)) + m_scriptController->addUserScript(*script.d, contents.data()); + m_contents = contents; +} diff --git a/src/core/compositor/display_producer.h b/src/core/api/qwebenginescriptcollection.h index 5de09d2d2..2a1ab7dbf 100644 --- a/src/core/compositor/display_producer.h +++ b/src/core/api/qwebenginescriptcollection.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2019 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtWebEngine module of the Qt Toolkit. @@ -37,33 +37,43 @@ ** ****************************************************************************/ -#ifndef DISPLAY_PRODUCER_H -#define DISPLAY_PRODUCER_H +#ifndef QWEBENGINESCRIPTCOLLECTION_H +#define QWEBENGINESCRIPTCOLLECTION_H -#include "qtwebenginecoreglobal_p.h" +#include <QtWebEngineCore/qtwebenginecoreglobal.h> +#include <QtWebEngineCore/qwebenginescript.h> +#include <QtCore/qscopedpointer.h> +#include <QtCore/qlist.h> +#include <QtCore/qset.h> QT_BEGIN_NAMESPACE -class QSGNode; -QT_END_NAMESPACE - -namespace QtWebEngineCore { -class RenderWidgetHostViewQtDelegate; +class QWebEngineScriptCollectionPrivate; -// Produces composited frames for display. -class DisplayProducer -{ +class Q_WEBENGINECORE_EXPORT QWebEngineScriptCollection { public: - // Generate scene graph nodes for the current frame. - // - // If this is a scheduled update (that is, scheduleUpdate was called - // earlier), then updatePaintNode will generate nodes for a new frame. - // Otherwise, it will just regenerate nodes for the old frame. - virtual QSGNode *updatePaintNode(QSGNode *oldNode, RenderWidgetHostViewQtDelegate *delegate) = 0; + ~QWebEngineScriptCollection(); -protected: - ~DisplayProducer() {} -}; + bool isEmpty() const { return !count(); } + int count() const; + bool contains(const QWebEngineScript &value) const; + QList<QWebEngineScript> find(const QString &name) const; + void insert(const QWebEngineScript &); + void insert(const QList<QWebEngineScript> &list); + bool remove(const QWebEngineScript &); + void clear(); + + QList<QWebEngineScript> toList() const; -} // namespace QtWebEngineCore +private: + Q_DISABLE_COPY(QWebEngineScriptCollection) + friend class QWebEnginePagePrivate; + friend class QWebEngineProfilePrivate; + friend class QQuickWebEngineProfilePrivate; + friend class QQuickWebEngineViewPrivate; + QWebEngineScriptCollection(QWebEngineScriptCollectionPrivate *); -#endif // !DISPLAY_PRODUCER_H + QScopedPointer<QWebEngineScriptCollectionPrivate> d; +}; + +QT_END_NAMESPACE +#endif // QWEBENGINESCRIPTCOLLECTION_H diff --git a/src/core/compositor/display_consumer.h b/src/core/api/qwebenginescriptcollection_p.h index d220088ad..442f8fe3d 100644 --- a/src/core/compositor/display_consumer.h +++ b/src/core/api/qwebenginescriptcollection_p.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2019 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtWebEngine module of the Qt Toolkit. @@ -37,26 +37,50 @@ ** ****************************************************************************/ -#ifndef DISPLAY_CONSUMER_H -#define DISPLAY_CONSUMER_H +#ifndef QWEBENGINESCRIPTCOLLECTION_P_H +#define QWEBENGINESCRIPTCOLLECTION_P_H -#include "qtwebenginecoreglobal_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 "qtwebenginecoreglobal.h" +#include "qwebenginescript.h" +#include "web_contents_adapter.h" + +#include <QtCore/QSet> +#include <QtCore/QSharedPointer> namespace QtWebEngineCore { +class UserResourceControllerHost; +} // namespace -// Receives composited frames for display. -class DisplayConsumer -{ +QT_BEGIN_NAMESPACE +class Q_WEBENGINECORE_PRIVATE_EXPORT QWebEngineScriptCollectionPrivate { public: - // Schedule a call to updatePaintNode soon. - // - // Called on the consumer thread. - virtual void scheduleUpdate() = 0; + QWebEngineScriptCollectionPrivate(QtWebEngineCore::UserResourceControllerHost *, QSharedPointer<QtWebEngineCore::WebContentsAdapter> = QSharedPointer<QtWebEngineCore::WebContentsAdapter>()); + int count() const; + bool contains(const QWebEngineScript &) const; + QList<QWebEngineScript> toList(const QString &scriptName = QString()) const; + void initializationFinished(QSharedPointer<QtWebEngineCore::WebContentsAdapter> contents); + void insert(const QWebEngineScript &); + bool remove(const QWebEngineScript &); + void clear(); + void reserve(int); -protected: - ~DisplayConsumer() {} +private: + QtWebEngineCore::UserResourceControllerHost *m_scriptController; + QSharedPointer<QtWebEngineCore::WebContentsAdapter> m_contents; + QList<QWebEngineScript> m_scripts; }; -} // namespace QtWebEngineCore +QT_END_NAMESPACE -#endif // !DISPLAY_CONSUMER_H +#endif // QWEBENGINESCRIPTCOLLECTION__PH diff --git a/src/core/api/qwebenginesettings.cpp b/src/core/api/qwebenginesettings.cpp new file mode 100644 index 000000000..c7c0a47b2 --- /dev/null +++ b/src/core/api/qwebenginesettings.cpp @@ -0,0 +1,142 @@ +/**************************************************************************** +** +** Copyright (C) 2020 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 "qwebenginesettings.h" +#include "web_engine_settings.h" + +QT_BEGIN_NAMESPACE + +using QtWebEngineCore::WebEngineSettings; + +QWebEngineSettings::QWebEngineSettings(QWebEngineSettings *parentSettings) + : d_ptr(new WebEngineSettings(parentSettings ? parentSettings->d_ptr.data() : nullptr)) +{ + d_ptr->scheduleApplyRecursively(); +} + +QWebEngineSettings::~QWebEngineSettings() { } + +/*! + Returns the settings for a web engine page that belongs to the default + profile. All web pages not specifically created with another profile belong + to the default profile. + +QWebEngineSettings *QWebEngineSettings::defaultSettings() +{ + return QWebEngineProfile::defaultProfile()->settings(); +} +*/ + +void QWebEngineSettings::setFontFamily(QWebEngineSettings::FontFamily which, const QString &family) +{ + d_ptr->setFontFamily(which, family); +} + +QString QWebEngineSettings::fontFamily(QWebEngineSettings::FontFamily which) const +{ + return d_ptr->fontFamily(which); +} + +void QWebEngineSettings::resetFontFamily(QWebEngineSettings::FontFamily which) +{ + d_ptr->resetFontFamily(which); +} + +void QWebEngineSettings::setFontSize(QWebEngineSettings::FontSize type, int size) +{ + d_ptr->setFontSize(type, size); +} + +int QWebEngineSettings::fontSize(QWebEngineSettings::FontSize type) const +{ + return d_ptr->fontSize(type); +} + +void QWebEngineSettings::resetFontSize(QWebEngineSettings::FontSize type) +{ + d_ptr->resetFontSize(type); +} + +QString QWebEngineSettings::defaultTextEncoding() const +{ + return d_ptr->defaultTextEncoding(); +} + +QWebEngineSettings::UnknownUrlSchemePolicy QWebEngineSettings::unknownUrlSchemePolicy() const +{ + return d_ptr->unknownUrlSchemePolicy(); +} + +void QWebEngineSettings::resetUnknownUrlSchemePolicy() +{ + d_ptr->setUnknownUrlSchemePolicy(QWebEngineSettings::InheritedUnknownUrlSchemePolicy); +} + +void QWebEngineSettings::setAttribute(QWebEngineSettings::WebAttribute attr, bool on) +{ + d_ptr->setAttribute(attr, on); +} + +bool QWebEngineSettings::testAttribute(QWebEngineSettings::WebAttribute attr) const +{ + return d_ptr->testAttribute(attr); +} + +void QWebEngineSettings::resetAttribute(QWebEngineSettings::WebAttribute attr) +{ + d_ptr->resetAttribute(attr); +} + +void QWebEngineSettings::setDefaultTextEncoding(const QString &encoding) +{ + d_ptr->setDefaultTextEncoding(encoding); +} + +void QWebEngineSettings::setUnknownUrlSchemePolicy( + QWebEngineSettings::UnknownUrlSchemePolicy policy) +{ + d_ptr->setUnknownUrlSchemePolicy(policy); +} + +void QWebEngineSettings::setParentSettings(QWebEngineSettings *parentSettings) +{ + d_ptr->setParentSettings(parentSettings->d_ptr.data()); +} + +QT_END_NAMESPACE diff --git a/src/core/api/qwebenginesettings.h b/src/core/api/qwebenginesettings.h new file mode 100644 index 000000000..f565f8ee2 --- /dev/null +++ b/src/core/api/qwebenginesettings.h @@ -0,0 +1,154 @@ +/**************************************************************************** +** +** Copyright (C) 2020 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 QWEBENGINESETTINGS_H +#define QWEBENGINESETTINGS_H + +#include <QtWebEngineCore/qtwebenginecoreglobal.h> +#include <QtCore/qscopedpointer.h> +#include <QtCore/qstring.h> + +namespace QtWebEngineCore { +class WebEngineSettings; +} + +QT_BEGIN_NAMESPACE + +class QIcon; +class QPixmap; +class QUrl; + +class Q_WEBENGINECORE_EXPORT QWebEngineSettings { +public: + enum FontFamily { + StandardFont, + FixedFont, + SerifFont, + SansSerifFont, + CursiveFont, + FantasyFont, + PictographFont + }; + + enum WebAttribute { + AutoLoadImages, + JavascriptEnabled, + JavascriptCanOpenWindows, + JavascriptCanAccessClipboard, + LinksIncludedInFocusChain, + LocalStorageEnabled, + LocalContentCanAccessRemoteUrls, + XSSAuditingEnabled, + SpatialNavigationEnabled, + LocalContentCanAccessFileUrls, + HyperlinkAuditingEnabled, + ScrollAnimatorEnabled, + ErrorPageEnabled, + PluginsEnabled, + FullScreenSupportEnabled, + ScreenCaptureEnabled, + WebGLEnabled, + Accelerated2dCanvasEnabled, + AutoLoadIconsForPage, + TouchIconsEnabled, + FocusOnNavigationEnabled, + PrintElementBackgrounds, + AllowRunningInsecureContent, + AllowGeolocationOnInsecureOrigins, + AllowWindowActivationFromJavaScript, + ShowScrollBars, + PlaybackRequiresUserGesture, + WebRTCPublicInterfacesOnly, + JavascriptCanPaste, + DnsPrefetchEnabled, + PdfViewerEnabled, + }; + + enum FontSize { + MinimumFontSize, + MinimumLogicalFontSize, + DefaultFontSize, + DefaultFixedFontSize + }; + + enum UnknownUrlSchemePolicy { + InheritedUnknownUrlSchemePolicy = 0, // TODO: hide + DisallowUnknownUrlSchemes = 1, + AllowUnknownUrlSchemesFromUserInteraction, + AllowAllUnknownUrlSchemes + }; + + //TODO: see if we still need it + //static QWebEngineSettings *defaultSettings(); +public: + ~QWebEngineSettings(); + void setFontFamily(FontFamily which, const QString &family); + QString fontFamily(FontFamily which) const; + void resetFontFamily(FontFamily which); + + void setFontSize(FontSize type, int size); + int fontSize(FontSize type) const; + void resetFontSize(FontSize type); + + void setAttribute(WebAttribute attr, bool on); + bool testAttribute(WebAttribute attr) const; + void resetAttribute(WebAttribute attr); + + void setDefaultTextEncoding(const QString &encoding); + QString defaultTextEncoding() const; + + UnknownUrlSchemePolicy unknownUrlSchemePolicy() const; + void setUnknownUrlSchemePolicy(UnknownUrlSchemePolicy policy); + void resetUnknownUrlSchemePolicy(); + +private: + explicit QWebEngineSettings(QWebEngineSettings *parentSettings = nullptr); + void setParentSettings(QWebEngineSettings *parentSettings); + Q_DISABLE_COPY(QWebEngineSettings) + typedef ::QtWebEngineCore::WebEngineSettings QWebEngineSettingsPrivate; + QScopedPointer<QWebEngineSettingsPrivate> d_ptr; + friend class QWebEnginePagePrivate; + friend class QWebEngineProfilePrivate; + friend class QQuickWebEngineSettings; + friend class QtWebEngineCore::WebEngineSettings; +}; + +QT_END_NAMESPACE + +#endif // QWEBENGINESETTINGS_H diff --git a/src/core/browser_accessibility_manager_qt.h b/src/core/browser_accessibility_manager_qt.h index 6d6086811..511f6bf9a 100644 --- a/src/core/browser_accessibility_manager_qt.h +++ b/src/core/browser_accessibility_manager_qt.h @@ -47,9 +47,7 @@ #if QT_CONFIG(accessibility) -QT_BEGIN_NAMESPACE -class QAccessibleInterface; -QT_END_NAMESPACE +QT_FORWARD_DECLARE_CLASS(QAccessibleInterface) namespace content { diff --git a/src/core/certificate_error_controller.cpp b/src/core/certificate_error_controller.cpp index d9043bf8e..0c0137ca4 100644 --- a/src/core/certificate_error_controller.cpp +++ b/src/core/certificate_error_controller.cpp @@ -38,7 +38,6 @@ ****************************************************************************/ #include "certificate_error_controller.h" -#include "certificate_error_controller_p.h" #include <net/base/net_errors.h> #include <net/cert/x509_certificate.h> @@ -48,94 +47,136 @@ #include "components/strings/grit/components_strings.h" #include "type_conversion.h" -QT_BEGIN_NAMESPACE - -using namespace QtWebEngineCore; - -ASSERT_ENUMS_MATCH(CertificateErrorController::SslPinnedKeyNotInCertificateChain, net::ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN) -ASSERT_ENUMS_MATCH(CertificateErrorController::CertificateCommonNameInvalid, net::ERR_CERT_COMMON_NAME_INVALID) -ASSERT_ENUMS_MATCH(CertificateErrorController::CertificateDateInvalid, net::ERR_CERT_DATE_INVALID) -ASSERT_ENUMS_MATCH(CertificateErrorController::CertificateAuthorityInvalid, net::ERR_CERT_AUTHORITY_INVALID) -ASSERT_ENUMS_MATCH(CertificateErrorController::CertificateContainsErrors, net::ERR_CERT_CONTAINS_ERRORS) -ASSERT_ENUMS_MATCH(CertificateErrorController::CertificateUnableToCheckRevocation, net::ERR_CERT_UNABLE_TO_CHECK_REVOCATION) -ASSERT_ENUMS_MATCH(CertificateErrorController::CertificateRevoked, net::ERR_CERT_REVOKED) -ASSERT_ENUMS_MATCH(CertificateErrorController::CertificateInvalid, net::ERR_CERT_INVALID) -ASSERT_ENUMS_MATCH(CertificateErrorController::CertificateWeakSignatureAlgorithm, net::ERR_CERT_WEAK_SIGNATURE_ALGORITHM) -ASSERT_ENUMS_MATCH(CertificateErrorController::CertificateNonUniqueName, net::ERR_CERT_NON_UNIQUE_NAME) -ASSERT_ENUMS_MATCH(CertificateErrorController::CertificateWeakKey, net::ERR_CERT_WEAK_KEY) -ASSERT_ENUMS_MATCH(CertificateErrorController::CertificateNameConstraintViolation, net::ERR_CERT_NAME_CONSTRAINT_VIOLATION) -ASSERT_ENUMS_MATCH(CertificateErrorController::CertificateValidityTooLong, net::ERR_CERT_VALIDITY_TOO_LONG) -ASSERT_ENUMS_MATCH(CertificateErrorController::CertificateTransparencyRequired, net::ERR_CERTIFICATE_TRANSPARENCY_REQUIRED) -ASSERT_ENUMS_MATCH(CertificateErrorController::CertificateSymantecLegacy, net::ERR_CERT_SYMANTEC_LEGACY) -ASSERT_ENUMS_MATCH(CertificateErrorController::CertificateKnownInterceptionBlocked, net::ERR_CERT_KNOWN_INTERCEPTION_BLOCKED) -ASSERT_ENUMS_MATCH(CertificateErrorController::SslObsoleteVersion, net::ERR_SSL_OBSOLETE_VERSION) -ASSERT_ENUMS_MATCH(CertificateErrorController::CertificateErrorEnd, net::ERR_CERT_END) - -void CertificateErrorControllerPrivate::accept(bool accepted) +namespace QtWebEngineCore { + +ASSERT_ENUMS_MATCH(QWebEngineCertificateError::SslPinnedKeyNotInCertificateChain, + net::ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN) +ASSERT_ENUMS_MATCH(QWebEngineCertificateError::CertificateCommonNameInvalid, net::ERR_CERT_BEGIN) +ASSERT_ENUMS_MATCH(QWebEngineCertificateError::CertificateCommonNameInvalid, + net::ERR_CERT_COMMON_NAME_INVALID) +ASSERT_ENUMS_MATCH(QWebEngineCertificateError::CertificateDateInvalid, net::ERR_CERT_DATE_INVALID) +ASSERT_ENUMS_MATCH(QWebEngineCertificateError::CertificateAuthorityInvalid, + net::ERR_CERT_AUTHORITY_INVALID) +ASSERT_ENUMS_MATCH(QWebEngineCertificateError::CertificateContainsErrors, + net::ERR_CERT_CONTAINS_ERRORS) +ASSERT_ENUMS_MATCH(QWebEngineCertificateError::CertificateUnableToCheckRevocation, + net::ERR_CERT_UNABLE_TO_CHECK_REVOCATION) +ASSERT_ENUMS_MATCH(QWebEngineCertificateError::CertificateRevoked, net::ERR_CERT_REVOKED) +ASSERT_ENUMS_MATCH(QWebEngineCertificateError::CertificateInvalid, net::ERR_CERT_INVALID) +ASSERT_ENUMS_MATCH(QWebEngineCertificateError::CertificateWeakSignatureAlgorithm, + net::ERR_CERT_WEAK_SIGNATURE_ALGORITHM) +ASSERT_ENUMS_MATCH(QWebEngineCertificateError::CertificateNonUniqueName, + net::ERR_CERT_NON_UNIQUE_NAME) +ASSERT_ENUMS_MATCH(QWebEngineCertificateError::CertificateWeakKey, net::ERR_CERT_WEAK_KEY) +ASSERT_ENUMS_MATCH(QWebEngineCertificateError::CertificateNameConstraintViolation, + net::ERR_CERT_NAME_CONSTRAINT_VIOLATION) +ASSERT_ENUMS_MATCH(QWebEngineCertificateError::CertificateValidityTooLong, + net::ERR_CERT_VALIDITY_TOO_LONG) +ASSERT_ENUMS_MATCH(QWebEngineCertificateError::CertificateTransparencyRequired, + net::ERR_CERTIFICATE_TRANSPARENCY_REQUIRED) +ASSERT_ENUMS_MATCH(QWebEngineCertificateError::CertificateSymantecLegacy, + net::ERR_CERT_SYMANTEC_LEGACY) +ASSERT_ENUMS_MATCH(QWebEngineCertificateError::CertificateKnownInterceptionBlocked, + net::ERR_CERT_KNOWN_INTERCEPTION_BLOCKED) +ASSERT_ENUMS_MATCH(QWebEngineCertificateError::SslObsoleteVersion, + net::ERR_SSL_OBSOLETE_VERSION) +// ASSERT_ENUMS_MATCH(QWebEngineCertificateError::CertificateErrorEnd, net::ERR_CERT_END) + +// Copied from chrome/browser/ssl/ssl_error_handler.cc: +static int IsCertErrorFatal(int cert_error) { - std::move(callback).Run(accepted ? content::CERTIFICATE_REQUEST_RESULT_TYPE_CONTINUE : content::CERTIFICATE_REQUEST_RESULT_TYPE_DENY); + switch (cert_error) { + case net::ERR_CERT_COMMON_NAME_INVALID: + case net::ERR_CERT_DATE_INVALID: + case net::ERR_CERT_AUTHORITY_INVALID: + case net::ERR_CERT_NO_REVOCATION_MECHANISM: + case net::ERR_CERT_UNABLE_TO_CHECK_REVOCATION: + case net::ERR_CERT_WEAK_SIGNATURE_ALGORITHM: + case net::ERR_CERT_WEAK_KEY: + case net::ERR_CERT_NAME_CONSTRAINT_VIOLATION: + case net::ERR_CERT_VALIDITY_TOO_LONG: + case net::ERR_CERTIFICATE_TRANSPARENCY_REQUIRED: + case net::ERR_CERT_SYMANTEC_LEGACY: + case net::ERR_CERT_KNOWN_INTERCEPTION_BLOCKED: + case net::ERR_SSL_OBSOLETE_VERSION: + return false; + case net::ERR_CERT_CONTAINS_ERRORS: + case net::ERR_CERT_REVOKED: + case net::ERR_CERT_INVALID: + case net::ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN: + return true; + default: + NOTREACHED(); + } + return true; } -CertificateErrorControllerPrivate::CertificateErrorControllerPrivate(int cert_error, - const net::SSLInfo& ssl_info, - const GURL &request_url, - bool main_frame, - bool fatal_error, - bool strict_enforcement, - base::OnceCallback<void(content::CertificateRequestResultType)> cb - ) - : certError(CertificateErrorController::CertificateError(cert_error)) - , requestUrl(toQt(request_url)) - , resourceType(main_frame ? CertificateErrorController::ResourceTypeMainFrame : CertificateErrorController::ResourceTypeOther) - , fatalError(fatal_error) - , strictEnforcement(strict_enforcement) - , callback(std::move(cb)) +CertificateErrorController::CertificateErrorController( + int cert_error, const net::SSLInfo &ssl_info, const GURL &request_url, + bool strict_enforcement, base::OnceCallback<void(content::CertificateRequestResultType)> cb) + : m_certError(QWebEngineCertificateError::Type(cert_error)) + , m_requestUrl(toQt(request_url)) + , m_overridable(!IsCertErrorFatal(cert_error) && !strict_enforcement) { + if (m_overridable) + m_callback = std::move(cb); if (auto cert = ssl_info.cert.get()) { - validStart = toQt(cert->valid_start()); - validExpiry = toQt(cert->valid_expiry()); - certificateChain = toCertificateChain(cert); + m_validExpiry = toQt(cert->valid_expiry()); + m_certificateChain = toCertificateChain(cert); } } -CertificateErrorController::CertificateErrorController(CertificateErrorControllerPrivate *p) : d(p) -{ -} - CertificateErrorController::~CertificateErrorController() { - delete d; - d = 0; + if (!answered()) + rejectCertificate(); } -CertificateErrorController::CertificateError CertificateErrorController::error() const +QWebEngineCertificateError::Type CertificateErrorController::error() const { - return d->certError; + return m_certError; } QUrl CertificateErrorController::url() const { - return d->requestUrl; + return m_requestUrl; } bool CertificateErrorController::overridable() const { - return !d->fatalError && !d->strictEnforcement; + return m_overridable; +} + +bool CertificateErrorController::deferred() const +{ + return m_deferred; +} + +void CertificateErrorController::defer() +{ + m_deferred = true; } -bool CertificateErrorController::strictEnforcement() const +bool CertificateErrorController::answered() const { - return d->strictEnforcement; + return m_answered; } void CertificateErrorController::accept(bool accepted) { - d->accept(accepted); + if (answered()) + return; + + m_answered = true; + if (m_callback) + std::move(m_callback) + .Run(accepted ? content::CERTIFICATE_REQUEST_RESULT_TYPE_CONTINUE + : content::CERTIFICATE_REQUEST_RESULT_TYPE_DENY); } -CertificateErrorController::ResourceType CertificateErrorController::resourceType() const +void CertificateErrorController::deactivate() { - return d->resourceType; + m_callback.Reset(); } static QString getQStringForMessageId(int message_id) { @@ -148,43 +189,43 @@ QString CertificateErrorController::errorString() const // Try to use chromiums translation of the error strings, though not all are // consistently described and we need to use versions that does not contain HTML // formatted text. - switch (d->certError) { - case SslPinnedKeyNotInCertificateChain: + switch (m_certError) { + case QWebEngineCertificateError::SslPinnedKeyNotInCertificateChain: return getQStringForMessageId(IDS_CERT_ERROR_SUMMARY_PINNING_FAILURE_DETAILS); - case CertificateCommonNameInvalid: + case QWebEngineCertificateError::CertificateCommonNameInvalid: return getQStringForMessageId(IDS_CERT_ERROR_COMMON_NAME_INVALID_DESCRIPTION); - case CertificateDateInvalid: - if (QDateTime::currentDateTime() > d->validExpiry) + case QWebEngineCertificateError::CertificateDateInvalid: + if (QDateTime::currentDateTime() > m_validExpiry) return getQStringForMessageId(IDS_CERT_ERROR_EXPIRED_DESCRIPTION); else return getQStringForMessageId(IDS_CERT_ERROR_NOT_YET_VALID_DESCRIPTION); - case CertificateAuthorityInvalid: - case CertificateKnownInterceptionBlocked: - case CertificateSymantecLegacy: + case QWebEngineCertificateError::CertificateAuthorityInvalid: + case QWebEngineCertificateError::CertificateKnownInterceptionBlocked: + case QWebEngineCertificateError::CertificateSymantecLegacy: return getQStringForMessageId(IDS_CERT_ERROR_AUTHORITY_INVALID_DESCRIPTION); - case CertificateContainsErrors: + case QWebEngineCertificateError::CertificateContainsErrors: return getQStringForMessageId(IDS_CERT_ERROR_CONTAINS_ERRORS_DESCRIPTION); - case CertificateNoRevocationMechanism: + case QWebEngineCertificateError::CertificateNoRevocationMechanism: return getQStringForMessageId(IDS_CERT_ERROR_NO_REVOCATION_MECHANISM_DESCRIPTION); - case CertificateRevoked: + case QWebEngineCertificateError::CertificateRevoked: return getQStringForMessageId(IDS_CERT_ERROR_REVOKED_CERT_DESCRIPTION); - case CertificateInvalid: + case QWebEngineCertificateError::CertificateInvalid: return getQStringForMessageId(IDS_CERT_ERROR_INVALID_CERT_DESCRIPTION); - case CertificateWeakSignatureAlgorithm: + case QWebEngineCertificateError::CertificateWeakSignatureAlgorithm: return getQStringForMessageId(IDS_CERT_ERROR_WEAK_SIGNATURE_ALGORITHM_DESCRIPTION); - case CertificateNonUniqueName: + case QWebEngineCertificateError::CertificateNonUniqueName: return getQStringForMessageId(IDS_PAGE_INFO_SECURITY_TAB_NON_UNIQUE_NAME); - case CertificateWeakKey: + case QWebEngineCertificateError::CertificateWeakKey: return getQStringForMessageId(IDS_CERT_ERROR_WEAK_KEY_DESCRIPTION); - case CertificateNameConstraintViolation: + case QWebEngineCertificateError::CertificateNameConstraintViolation: return getQStringForMessageId(IDS_CERT_ERROR_NAME_CONSTRAINT_VIOLATION_DESCRIPTION); - case CertificateValidityTooLong: + case QWebEngineCertificateError::CertificateValidityTooLong: return getQStringForMessageId(IDS_CERT_ERROR_VALIDITY_TOO_LONG_DESCRIPTION); - case CertificateTransparencyRequired: + case QWebEngineCertificateError::CertificateTransparencyRequired: return getQStringForMessageId(IDS_CERT_ERROR_CERTIFICATE_TRANSPARENCY_REQUIRED_DESCRIPTION); - case SslObsoleteVersion: + case QWebEngineCertificateError::SslObsoleteVersion: return getQStringForMessageId(IDS_SSL_ERROR_OBSOLETE_VERSION_DESCRIPTION); - case CertificateUnableToCheckRevocation: // Deprecated in Chromium. + case QWebEngineCertificateError::CertificateUnableToCheckRevocation: // Deprecated in Chromium. default: break; } @@ -194,7 +235,7 @@ QString CertificateErrorController::errorString() const QList<QSslCertificate> CertificateErrorController::certificateChain() const { - return d->certificateChain; + return m_certificateChain; } -QT_END_NAMESPACE +} diff --git a/src/core/certificate_error_controller.h b/src/core/certificate_error_controller.h index 740f7a9d4..ec3e26806 100644 --- a/src/core/certificate_error_controller.h +++ b/src/core/certificate_error_controller.h @@ -52,84 +52,59 @@ #define CERTIFICATE_ERROR_CONTROLLER_H #include "qtwebenginecoreglobal_p.h" - +#include "base/callback.h" +#include "content/public/browser/certificate_request_result_type.h" +#include "qwebenginecertificateerror.h" #include <QtCore/QDateTime> +#include <QtCore/QScopedPointer> #include <QtCore/QUrl> #include <QtNetwork/QSslCertificate> -QT_BEGIN_NAMESPACE +namespace net { +class SSLInfo; +} +class GURL; -class CertificateErrorControllerPrivate; +namespace QtWebEngineCore { class Q_WEBENGINECORE_PRIVATE_EXPORT CertificateErrorController { public: - CertificateErrorController(CertificateErrorControllerPrivate *p); + CertificateErrorController( + int cert_error, const net::SSLInfo &ssl_info, const GURL &request_url, + bool strict_enforcement, + base::OnceCallback<void(content::CertificateRequestResultType)> callback); ~CertificateErrorController(); - // We can't use QSslError::SslErrors, because the error categories doesn't map. - // Keep up to date with net/base/net_errors.h and net::IsCertificateError(): - enum CertificateError { - SslPinnedKeyNotInCertificateChain = -150, - CertificateCommonNameInvalid = -200, - CertificateDateInvalid = -201, - CertificateAuthorityInvalid = -202, - CertificateContainsErrors = -203, - CertificateNoRevocationMechanism = -204, - CertificateUnableToCheckRevocation = -205, - CertificateRevoked = -206, - CertificateInvalid = -207, - CertificateWeakSignatureAlgorithm = -208, - CertificateNonUniqueName = -210, - CertificateWeakKey = -211, - CertificateNameConstraintViolation = -212, - CertificateValidityTooLong = -213, - CertificateTransparencyRequired = -214, - CertificateSymantecLegacy = -215, - CertificateKnownInterceptionBlocked = -217, - SslObsoleteVersion = -218, - CertificateErrorEnd = -219 // not an error, just an enum boundary - }; - - CertificateError error() const; + QWebEngineCertificateError::Type error() const; QUrl url() const; bool overridable() const; - bool strictEnforcement() const; QString errorString() const; - QDateTime validStart() const; QDateTime validExpiry() const; QList<QSslCertificate> certificateChain() const; + bool deferred() const; + void defer(); + + bool answered() const; void accept(bool); - // Note: The resource type should probably not be exported, since once accepted the certificate exception - // counts for all resource types. - // Keep up to date with webkit/common/resource_type.h - enum ResourceType { - ResourceTypeMainFrame = 0, // top level page - ResourceTypeSubFrame, // frame or iframe - ResourceTypeStylesheet, // a CSS stylesheet - ResourceTypeScript, // an external script - ResourceTypeImage, // an image (jpg/gif/png/etc) - ResourceTypeFont, // a font - ResourceTypeOther, // an "other" subresource. - ResourceTypeObject, // an object (or embed) tag for a plugin, - // or a resource that a plugin requested. - ResourceTypeMedia, // a media resource. - ResourceTypeWorker, // the main resource of a dedicated worker. - ResourceTypeSharedWorker, // the main resource of a shared worker. - ResourceTypePrefetch, // an explicitly requested prefetch - ResourceTypeFavicon, // a favicon - ResourceTypeXHR, // a XMLHttpRequest - ResourceTypePing, // a ping request for <a ping> - ResourceTypeServiceWorker, // the main resource of a service worker. - }; + void ignoreCertificateError() { accept(true); } + void rejectCertificate() { accept(false); } - ResourceType resourceType() const; + void deactivate(); + + QWebEngineCertificateError::Type m_certError; + const QUrl m_requestUrl; + QDateTime m_validExpiry; + bool m_overridable; + base::OnceCallback<void(content::CertificateRequestResultType)> m_callback; + QList<QSslCertificate> m_certificateChain; + + bool m_answered = false, m_deferred = false; private: - CertificateErrorControllerPrivate* d; + Q_DISABLE_COPY(CertificateErrorController) }; -QT_END_NAMESPACE - +} #endif // CERTIFICATE_ERROR_CONTROLLER_H diff --git a/src/core/client_cert_select_controller.cpp b/src/core/client_cert_select_controller.cpp index 0baaf2bc5..2f2d24716 100644 --- a/src/core/client_cert_select_controller.cpp +++ b/src/core/client_cert_select_controller.cpp @@ -50,9 +50,7 @@ #include <QDebug> -QT_BEGIN_NAMESPACE - -using namespace QtWebEngineCore; +namespace QtWebEngineCore { ClientCertSelectController::ClientCertSelectController(net::SSLCertRequestInfo *certRequestInfo, std::vector<std::unique_ptr<net::ClientCertIdentity>> clientCerts, @@ -73,8 +71,6 @@ ClientCertSelectController::~ClientCertSelectController() m_delegate->ContinueWithCertificate(nullptr, nullptr); } -#if !defined(QT_NO_SSL) || QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) - void ClientCertSelectController::selectNone() { if (m_selected) { @@ -132,7 +128,7 @@ void ClientCertSelectController::select(const QSslCertificate &certificate) << " Selected certificate needs to be one of the offered"; } -QVector<QSslCertificate> ClientCertSelectController::certificates() const +QList<QSslCertificate> ClientCertSelectController::certificates() const { if (!m_certificates.isEmpty()) return m_certificates; @@ -144,6 +140,4 @@ QVector<QSslCertificate> ClientCertSelectController::certificates() const return m_certificates; } -#endif // !defined(QT_NO_SSL) || QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) - -QT_END_NAMESPACE +} diff --git a/src/core/client_cert_select_controller.h b/src/core/client_cert_select_controller.h index f121c1155..3a733f56f 100644 --- a/src/core/client_cert_select_controller.h +++ b/src/core/client_cert_select_controller.h @@ -55,10 +55,8 @@ #include <QtNetwork/qtnetwork-config.h> #include <QtCore/QUrl> -#if !defined(QT_NO_SSL) || QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) -#include <QtCore/QVector> +#include <QtCore/QList> #include <QtNetwork/QSslCertificate> -#endif #include <memory> namespace content { @@ -70,7 +68,7 @@ class ClientCertIdentity; class SSLCertRequestInfo; } -QT_BEGIN_NAMESPACE +namespace QtWebEngineCore { class Q_WEBENGINECORE_PRIVATE_EXPORT ClientCertSelectController { public: @@ -80,22 +78,20 @@ public: ~ClientCertSelectController(); QUrl hostAndPort() const { return m_hostAndPort; } -#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 + QList<QSslCertificate> certificates() const; 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; + mutable QList<QSslCertificate> m_certificates; bool m_selected; }; -QT_END_NAMESPACE +} #endif // CLIENT_CERT_SELECT_CONTROLLER_H diff --git a/src/core/common/user_script_data.cpp b/src/core/common/user_script_data.cpp index 6f4b8cb05..68840d2fa 100644 --- a/src/core/common/user_script_data.cpp +++ b/src/core/common/user_script_data.cpp @@ -41,8 +41,6 @@ #include "base/pickle.h" UserScriptData::UserScriptData() : injectionPoint(AfterLoad) - , injectForSubframes(false) - , worldId(1) { static uint64_t idCount = 0; scriptId = idCount++; diff --git a/src/core/common/user_script_data.h b/src/core/common/user_script_data.h index 8d98890e3..a2ca8c2ea 100644 --- a/src/core/common/user_script_data.h +++ b/src/core/common/user_script_data.h @@ -56,9 +56,9 @@ struct UserScriptData { std::string source; GURL url; - /*InjectionPoint*/uint8_t injectionPoint; - bool injectForSubframes; - uint worldId; + uint8_t injectionPoint = AfterLoad; + bool injectForSubframes = false; + uint worldId = 1; uint64_t scriptId; std::vector<std::string> globs; std::vector<std::string> excludeGlobs; diff --git a/src/core/compositor/compositor.cpp b/src/core/compositor/compositor.cpp new file mode 100644 index 000000000..655126f20 --- /dev/null +++ b/src/core/compositor/compositor.cpp @@ -0,0 +1,197 @@ +/**************************************************************************** +** +** Copyright (C) 2020 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.h" + +#include "base/memory/ref_counted.h" +#include "components/viz/common/surfaces/frame_sink_id.h" + +#include <QHash> +#include <QImage> +#include <QMutex> + +namespace QtWebEngineCore { + +// Compositor::Id + +Compositor::Id::Id(viz::FrameSinkId fid) : client_id(fid.client_id()), sink_id(fid.sink_id()) { } + +static size_t qHash(Compositor::Id id, size_t seed = 0) +{ + QtPrivate::QHashCombine hasher; + seed = hasher(seed, id.client_id); + seed = hasher(seed, id.sink_id); + return seed; +} + +static bool operator==(Compositor::Id id1, Compositor::Id id2) +{ + return id1.client_id == id2.client_id && id1.sink_id == id2.sink_id; +} + +// Compositor::Binding and Compositor::Bindings + +struct Compositor::Binding +{ + const Id id; + Compositor *compositor = nullptr; + Observer *observer = nullptr; + + Binding(Id id) : id(id) { } + ~Binding(); +}; + +class Compositor::BindingMap +{ +public: + void lock() { m_mutex.lock(); } + + void unlock() { m_mutex.unlock(); } + + Binding *findOrCreate(Id id) + { + auto it = m_map.find(id); + if (it == m_map.end()) + it = m_map.insert(id, new Binding(id)); + return *it; + } + + void remove(Id id) { m_map.remove(id); } + +private: + QMutex m_mutex; + QHash<Id, Binding *> m_map; +} static g_bindings; + +Compositor::Binding::~Binding() +{ + g_bindings.remove(id); +} + +// Compositor::Observer + +void Compositor::Observer::bind(Id id) +{ + DCHECK(!m_binding); + g_bindings.lock(); + m_binding = g_bindings.findOrCreate(id); + DCHECK(!m_binding->observer); + m_binding->observer = this; + g_bindings.unlock(); +} + +void Compositor::Observer::unbind() +{ + DCHECK(m_binding); + g_bindings.lock(); + m_binding->observer = nullptr; + if (m_binding->compositor == nullptr) + delete m_binding; + m_binding = nullptr; + g_bindings.unlock(); +} + +Compositor::Handle<Compositor> Compositor::Observer::compositor() +{ + if (!m_binding) + return nullptr; + g_bindings.lock(); + if (m_binding->compositor) + return m_binding->compositor; // delay unlock + g_bindings.unlock(); + return nullptr; +} + +// Compositor + +void Compositor::bind(Id id) +{ + DCHECK(!m_binding); + g_bindings.lock(); + m_binding = g_bindings.findOrCreate(id); + DCHECK(!m_binding->compositor); + m_binding->compositor = this; + g_bindings.unlock(); +} + +void Compositor::unbind() +{ + DCHECK(m_binding); + g_bindings.lock(); + m_binding->compositor = nullptr; + if (m_binding->observer == nullptr) + delete m_binding; + m_binding = nullptr; + g_bindings.unlock(); +} + +Compositor::Handle<Compositor::Observer> Compositor::observer() +{ + if (!m_binding) + return nullptr; + g_bindings.lock(); + if (m_binding->observer) + return m_binding->observer; // delay unlock + g_bindings.unlock(); + return nullptr; +} + +QImage Compositor::image() +{ + Q_UNREACHABLE(); + return {}; +} + +void Compositor::waitForTexture() +{ + Q_UNREACHABLE(); +} + +int Compositor::textureId() +{ + Q_UNREACHABLE(); + return 0; +} + +// static +void Compositor::unlockBindings() +{ + g_bindings.unlock(); +} +} // namespace QtWebEngineCore diff --git a/src/core/compositor/compositor.h b/src/core/compositor/compositor.h new file mode 100644 index 000000000..316178891 --- /dev/null +++ b/src/core/compositor/compositor.h @@ -0,0 +1,195 @@ +/**************************************************************************** +** +** Copyright (C) 2020 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_H +#define COMPOSITOR_H + +#include "qtwebenginecoreglobal_p.h" + +QT_BEGIN_NAMESPACE +class QImage; +class QSize; +QT_END_NAMESPACE + +namespace viz { +class FrameSinkId; +} // namespace viz + +namespace QtWebEngineCore { + +// Produces composited frames for display. +// +// Used by quick/widgets libraries for accessing the frame and +// controlling frame swapping. Must be cast to a subclass to access +// the frame as QImage or OpenGL texture, etc. +class Q_WEBENGINECORE_PRIVATE_EXPORT Compositor +{ + struct Binding; + +public: + // Identifies the implementation type. + enum class Type { + Software, + OpenGL, + }; + + // Identifies a compositor. + // + // The purpose of assigning ids to compositors is to allow the + // corresponding observer to be registered before the compositor + // itself is created, which is necessary since the creation + // happens on a different thread in the depths of viz. + // + // (Maps to viz::FrameSinkId internally). + struct Id + { + quint32 client_id; + quint32 sink_id; + + Id(viz::FrameSinkId); + }; + + // Pointer to Compositor or Observer that holds a lock to prevent + // either from being unbound and destroyed. + template<typename T> + class Handle + { + public: + Handle(std::nullptr_t) : m_data(nullptr) { } + Handle(T *data) : m_data(data) { } + Handle(Handle &&that) : m_data(that.m_data) { that.m_data = nullptr; } + ~Handle() + { + if (m_data) + Compositor::unlockBindings(); + } + T *operator->() const { return m_data; } + T &operator*() const { return *m_data; } + explicit operator bool() const { return m_data; } + + private: + T *m_data; + }; + + // Observes the compositor corresponding to the given id. + // + // Only one observer can exist per compositor. + class Q_WEBENGINECORE_PRIVATE_EXPORT Observer + { + public: + // Binding to compositor + void bind(Id id); + void unbind(); + + // Compositor if bound + Handle<Compositor> compositor(); + + // There's a new frame ready, time to swapFrame(). + virtual void readyToSwap() = 0; + + protected: + Observer() = default; + ~Observer() = default; + + private: + Binding *m_binding = nullptr; + }; + + // Type determines which methods can be called. + Type type() const { return m_type; } + + // Binding to observer. + void bind(Id id); + void unbind(); + + // Observer if bound. + Handle<Observer> observer(); + + // Update to next frame if possible. + virtual void swapFrame() = 0; + + // Ratio of pixels to DIPs. + // + // Don't use the devicePixelRatio of QImage, it's always 1. + virtual float devicePixelRatio() = 0; + + // Size of frame in pixels. + virtual QSize size() = 0; + + // Whether frame needs an alpha channel. + // + // In software mode, the image format can be either + // QImage::Format_ARGB32_Premultiplied or + // QImage::Format_RGBA8888_Premultiplied + // + // In OpenGL mode, the texture format is either GL_RGBA or GL_RGB. + virtual bool hasAlphaChannel() = 0; + + // (Software) QImage of the frame. + // + // This is a big image so we should try not to make copies of it. + // In particular, the client should drop its QImage reference + // before calling swapFrame(), otherwise each swap will cause a + // detach. + virtual QImage image(); + + // (OpenGL) Wait on texture fence in Qt's current OpenGL context. + virtual void waitForTexture(); + + // (OpenGL) Texture of the frame. + virtual int textureId(); + +protected: + Compositor(Type type) : m_type(type) { } + ~Compositor() = default; + +private: + template<typename T> + friend class Handle; + + class BindingMap; + static void unlockBindings(); + + const Type m_type; + Binding *m_binding = nullptr; +}; + +} // namespace QtWebEngineCore + +#endif // !COMPOSITOR_H diff --git a/src/core/compositor/display_frame_sink.cpp b/src/core/compositor/display_frame_sink.cpp deleted file mode 100644 index 945600299..000000000 --- a/src/core/compositor/display_frame_sink.cpp +++ /dev/null @@ -1,140 +0,0 @@ -/**************************************************************************** -** -** 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 "display_frame_sink.h" - -#include <QMap> - -namespace QtWebEngineCore { - -namespace { - -class DisplayFrameSinkMap -{ -public: - static DisplayFrameSinkMap *instance() - { - static DisplayFrameSinkMap map; - return ↦ - } - - scoped_refptr<DisplayFrameSink> findOrCreate(viz::FrameSinkId frameSinkId) - { - QMutexLocker locker(&m_mutex); - auto it = m_map.find(frameSinkId); - if (it == m_map.end()) - it = m_map.insert(frameSinkId, new DisplayFrameSink(frameSinkId)); - return *it; - } - - void remove(viz::FrameSinkId frameSinkId) - { - QMutexLocker locker(&m_mutex); - m_map.remove(frameSinkId); - } - -private: - mutable QMutex m_mutex; - QMap<viz::FrameSinkId, DisplayFrameSink *> m_map; -}; - -} // namespace - -// static -scoped_refptr<DisplayFrameSink> DisplayFrameSink::findOrCreate(viz::FrameSinkId frameSinkId) -{ - return DisplayFrameSinkMap::instance()->findOrCreate(frameSinkId); -} - -DisplayFrameSink::DisplayFrameSink(viz::FrameSinkId frameSinkId) - : m_frameSinkId(frameSinkId) -{ - DCHECK(m_frameSinkId.is_valid()); -} - -DisplayFrameSink::~DisplayFrameSink() -{ - DisplayFrameSinkMap::instance()->remove(m_frameSinkId); -} - -void DisplayFrameSink::connect(DisplayConsumer *consumer) -{ - QMutexLocker locker(&m_mutex); - DCHECK(m_consumer == nullptr); - m_consumer = consumer; -} - -void DisplayFrameSink::connect(DisplayProducer *producer) -{ - QMutexLocker locker(&m_mutex); - DCHECK(m_producer == nullptr); - m_producer = producer; -} - -void DisplayFrameSink::disconnect(DisplayConsumer *consumer) -{ - QMutexLocker locker(&m_mutex); - DCHECK(m_consumer == consumer); - m_consumer = nullptr; -} - -void DisplayFrameSink::disconnect(DisplayProducer *producer) -{ - QMutexLocker locker(&m_mutex); - DCHECK(m_producer == producer); - m_producer = nullptr; -} - -void DisplayFrameSink::scheduleUpdate() -{ - QMutexLocker locker(&m_mutex); - if (m_consumer) - m_consumer->scheduleUpdate(); -} - -QSGNode *DisplayFrameSink::updatePaintNode(QSGNode *oldNode, RenderWidgetHostViewQtDelegate *delegate) -{ - QMutexLocker locker(&m_mutex); - QSGNode *newNode = oldNode; - if (m_producer) - newNode = m_producer->updatePaintNode(oldNode, delegate); - return newNode; -} - -} // namespace QtWebEngineCore diff --git a/src/core/compositor/display_gl_output_surface.cpp b/src/core/compositor/display_gl_output_surface.cpp index 370eb07e6..16a925bd4 100644 --- a/src/core/compositor/display_gl_output_surface.cpp +++ b/src/core/compositor/display_gl_output_surface.cpp @@ -39,6 +39,8 @@ #include "display_gl_output_surface.h" +#include "type_conversion.h" + #include "base/threading/thread_task_runner_handle.h" #include "components/viz/service/display/display.h" #include "components/viz/service/display/output_surface_frame.h" @@ -51,8 +53,10 @@ namespace QtWebEngineCore { -DisplayGLOutputSurface::DisplayGLOutputSurface(scoped_refptr<viz::VizProcessContextProvider> contextProvider) +DisplayGLOutputSurface::DisplayGLOutputSurface( + scoped_refptr<viz::VizProcessContextProvider> contextProvider) : OutputSurface(contextProvider) + , Compositor(Compositor::Type::OpenGL) , m_commandBuffer(contextProvider->command_buffer()) , m_gl(contextProvider->ContextGL()) , m_vizContextProvider(contextProvider) @@ -63,18 +67,16 @@ DisplayGLOutputSurface::DisplayGLOutputSurface(scoped_refptr<viz::VizProcessCont DisplayGLOutputSurface::~DisplayGLOutputSurface() { + unbind(); m_vizContextProvider->SetUpdateVSyncParametersCallback(viz::UpdateVSyncParametersCallback()); m_gl->DeleteFramebuffers(1, &m_fboId); - if (m_sink) - m_sink->disconnect(this); } // Called from viz::Display::Initialize. void DisplayGLOutputSurface::BindToClient(viz::OutputSurfaceClient *client) { m_display = static_cast<viz::Display *>(client); - m_sink = DisplayFrameSink::findOrCreate(m_display->frame_sink_id()); - m_sink->connect(this); + bind(m_display->frame_sink_id()); } // Triggered by ui::Compositor::SetVisible(true). @@ -213,7 +215,8 @@ void DisplayGLOutputSurface::swapBuffersOnGpuThread(unsigned int id, std::unique m_readyToUpdate = true; } - m_sink->scheduleUpdate(); + if (auto obs = observer()) + obs->readyToSwap(); } void DisplayGLOutputSurface::swapBuffersOnVizThread() @@ -300,4 +303,45 @@ gfx::OverlayTransform DisplayGLOutputSurface::GetDisplayTransform() return gfx::OVERLAY_TRANSFORM_NONE; } +void DisplayGLOutputSurface::swapFrame() +{ + QMutexLocker locker(&m_mutex); + if (m_readyToUpdate) { + std::swap(m_middleBuffer, m_frontBuffer); + m_taskRunner->PostTask(FROM_HERE, + base::BindOnce(&DisplayGLOutputSurface::swapBuffersOnVizThread, + base::Unretained(this))); + m_taskRunner.reset(); + m_readyToUpdate = false; + } +} + +void DisplayGLOutputSurface::waitForTexture() +{ + if (m_frontBuffer && m_frontBuffer->fence) { + m_frontBuffer->fence->wait(); + m_frontBuffer->fence.reset(); + } +} + +int DisplayGLOutputSurface::textureId() +{ + return m_frontBuffer ? m_frontBuffer->serviceId : 0; +} + +QSize DisplayGLOutputSurface::size() +{ + return m_frontBuffer ? toQt(m_frontBuffer->shape.sizeInPixels) : QSize(); +} + +bool DisplayGLOutputSurface::hasAlphaChannel() +{ + return m_frontBuffer ? m_frontBuffer->shape.hasAlpha : false; +} + +float DisplayGLOutputSurface::devicePixelRatio() +{ + return m_frontBuffer ? m_frontBuffer->shape.devicePixelRatio : 1; +} + } // namespace QtWebEngineCore diff --git a/src/core/compositor/display_gl_output_surface.h b/src/core/compositor/display_gl_output_surface.h index d2e203b4e..5c6b1ab23 100644 --- a/src/core/compositor/display_gl_output_surface.h +++ b/src/core/compositor/display_gl_output_surface.h @@ -41,7 +41,7 @@ #define DISPLAY_GL_OUTPUT_SURFACE_H #include "compositor_resource_fence.h" -#include "display_frame_sink.h" +#include "compositor.h" #include "components/viz/common/display/update_vsync_parameters_callback.h" #include "components/viz/service/display/output_surface.h" @@ -49,6 +49,8 @@ #include "gpu/command_buffer/common/mailbox.h" #include "gpu/command_buffer/common/sync_token.h" +#include <QMutex> + namespace viz { class Display; class SyntheticBeginFrameSource; @@ -56,9 +58,7 @@ class SyntheticBeginFrameSource; namespace QtWebEngineCore { -// NOTE: Some methods are defined in display_gl_output_surface_qsg.cpp due -// to conflicts between Qt & Chromium OpenGL APIs. -class DisplayGLOutputSurface final : public viz::OutputSurface, public DisplayProducer +class DisplayGLOutputSurface final : public viz::OutputSurface, public Compositor { public: DisplayGLOutputSurface(scoped_refptr<viz::VizProcessContextProvider> contextProvider); @@ -88,8 +88,13 @@ public: scoped_refptr<gpu::GpuTaskSchedulerHelper> GetGpuTaskSchedulerHelper() override; gpu::MemoryTracker *GetMemoryTracker() override; - // Overridden from DisplayProducer. - QSGNode *updatePaintNode(QSGNode *oldNode, RenderWidgetHostViewQtDelegate *delegate) override; + // Overridden from Compositor. + void swapFrame() override; + void waitForTexture() override; + int textureId() override; + QSize size() override; + bool hasAlphaChannel() override; + float devicePixelRatio() override; private: struct Shape @@ -136,7 +141,6 @@ private: mutable QMutex m_mutex; uint32_t m_fboId = 0; viz::Display *m_display = nullptr; - scoped_refptr<DisplayFrameSink> m_sink; Shape m_currentShape; std::unique_ptr<Buffer> m_backBuffer; std::unique_ptr<Buffer> m_middleBuffer; diff --git a/src/core/compositor/display_gl_output_surface_qsg.cpp b/src/core/compositor/display_gl_output_surface_qsg.cpp deleted file mode 100644 index 0e9fff6e3..000000000 --- a/src/core/compositor/display_gl_output_surface_qsg.cpp +++ /dev/null @@ -1,122 +0,0 @@ -/**************************************************************************** -** -** 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 "display_gl_output_surface.h" - -#include "compositor_resource_fence.h" -#include "render_widget_host_view_qt_delegate.h" -#include "type_conversion.h" - -#include <QOpenGLFunctions> -#include <QSGImageNode> -#include <QSGTexture> - -namespace QtWebEngineCore { - -class DisplayGLOutputSurface::Texture final : public QSGTexture -{ -public: - Texture(uint32_t id, QSize sizeInPixels, bool hasAlphaChannel, scoped_refptr<CompositorResourceFence> fence) - : m_id(id) - , m_sizeInPixels(sizeInPixels) - , m_hasAlphaChannel(hasAlphaChannel) - , m_fence(std::move(fence)) - { - } - - // QSGTexture: - int textureId() const override { return m_id; } - QSize textureSize() const override { return m_sizeInPixels; } - bool hasAlphaChannel() const override { return m_hasAlphaChannel; } - bool hasMipmaps() const override { return false; } - void bind() override - { - if (m_fence) { - m_fence->wait(); - m_fence.reset(); - } - - QOpenGLContext *context = QOpenGLContext::currentContext(); - QOpenGLFunctions *funcs = context->functions(); - funcs->glBindTexture(GL_TEXTURE_2D, m_id); - } - -private: - uint32_t m_id; - QSize m_sizeInPixels; - bool m_hasAlphaChannel; - scoped_refptr<CompositorResourceFence> m_fence; -}; - -QSGNode *DisplayGLOutputSurface::updatePaintNode(QSGNode *oldNode, RenderWidgetHostViewQtDelegate *delegate) -{ - { - QMutexLocker locker(&m_mutex); - if (m_readyToUpdate) { - std::swap(m_middleBuffer, m_frontBuffer); - m_taskRunner->PostTask( - FROM_HERE, - base::BindOnce(&DisplayGLOutputSurface::swapBuffersOnVizThread, base::Unretained(this))); - m_taskRunner.reset(); - m_readyToUpdate = false; - } - } - - if (!m_frontBuffer) - return oldNode; - - auto node = static_cast<QSGImageNode *>(oldNode); - if (!node) - node = delegate->createImageNode(); - - QSize sizeInPixels = toQt(m_frontBuffer->shape.sizeInPixels); - QSizeF sizeInDips = QSizeF(sizeInPixels) / m_frontBuffer->shape.devicePixelRatio; - QRectF rectInDips(QPointF(0, 0), sizeInDips); - node->setRect(rectInDips); - node->setOwnsTexture(true); - node->setTexture(new Texture(m_frontBuffer->serviceId, - sizeInPixels, - m_frontBuffer->shape.hasAlpha, - m_frontBuffer->fence)); - node->setTextureCoordinatesTransform(QSGImageNode::MirrorVertically); - - return node; -} - -} // namespace QtWebEngineCore diff --git a/src/core/compositor/display_software_output_surface.cpp b/src/core/compositor/display_software_output_surface.cpp index ba99799f0..218bff94a 100644 --- a/src/core/compositor/display_software_output_surface.cpp +++ b/src/core/compositor/display_software_output_surface.cpp @@ -39,7 +39,7 @@ #include "display_software_output_surface.h" -#include "display_frame_sink.h" +#include "compositor.h" #include "render_widget_host_view_qt_delegate.h" #include "type_conversion.h" @@ -49,28 +49,29 @@ #include <QMutex> #include <QPainter> -#include <QSGImageNode> namespace QtWebEngineCore { -class DisplaySoftwareOutputSurface::Device final : public viz::SoftwareOutputDevice, public DisplayProducer +class DisplaySoftwareOutputSurface::Device final : public viz::SoftwareOutputDevice, + public Compositor { public: + Device(); ~Device(); - // Called from DisplaySoftwareOutputSurface. - void bind(viz::FrameSinkId frameSinkId); - // Overridden from viz::SoftwareOutputDevice. void Resize(const gfx::Size &sizeInPixels, float devicePixelRatio) override; void OnSwapBuffers(SwapBuffersCallback swap_ack_callback) override; - // Overridden from DisplayProducer. - QSGNode *updatePaintNode(QSGNode *oldNode, RenderWidgetHostViewQtDelegate *delegate) override; + // Overridden from Compositor. + void swapFrame() override; + QImage image() override; + float devicePixelRatio() override; + QSize size() override; + bool hasAlphaChannel() override; private: mutable QMutex m_mutex; - scoped_refptr<DisplayFrameSink> m_sink; float m_devicePixelRatio = 1.0; scoped_refptr<base::SingleThreadTaskRunner> m_taskRunner; SwapBuffersCallback m_swapCompletionCallback; @@ -78,16 +79,13 @@ private: float m_imageDevicePixelRatio = 1.0; }; -DisplaySoftwareOutputSurface::Device::~Device() -{ - if (m_sink) - m_sink->disconnect(this); -} +DisplaySoftwareOutputSurface::Device::Device() + : Compositor(Type::Software) +{} -void DisplaySoftwareOutputSurface::Device::bind(viz::FrameSinkId frameSinkId) +DisplaySoftwareOutputSurface::Device::~Device() { - m_sink = DisplayFrameSink::findOrCreate(frameSinkId); - m_sink->connect(this); + unbind(); } void DisplaySoftwareOutputSurface::Device::Resize(const gfx::Size &sizeInPixels, float devicePixelRatio) @@ -104,7 +102,8 @@ void DisplaySoftwareOutputSurface::Device::OnSwapBuffers(SwapBuffersCallback swa QMutexLocker locker(&m_mutex); m_taskRunner = base::ThreadTaskRunnerHandle::Get(); m_swapCompletionCallback = std::move(swap_ack_callback); - m_sink->scheduleUpdate(); + if (auto obs = observer()) + obs->readyToSwap(); } inline QImage::Format imageFormat(SkColorType colorType) @@ -120,41 +119,51 @@ inline QImage::Format imageFormat(SkColorType colorType) } } -QSGNode *DisplaySoftwareOutputSurface::Device::updatePaintNode( - QSGNode *oldNode, RenderWidgetHostViewQtDelegate *delegate) +void DisplaySoftwareOutputSurface::Device::swapFrame() { QMutexLocker locker(&m_mutex); - // Delete old node to make sure refcount of m_image is at most 1. - delete oldNode; - QSGImageNode *node = delegate->createImageNode(); - - if (m_swapCompletionCallback) { - SkPixmap skPixmap; - surface_->peekPixels(&skPixmap); - QImage image(reinterpret_cast<const uchar *>(skPixmap.addr()), - viewport_pixel_size_.width(), viewport_pixel_size_.height(), - skPixmap.rowBytes(), imageFormat(skPixmap.colorType())); - if (m_image.size() == image.size()) { - QRect damageRect = toQt(damage_rect_); - QPainter painter(&m_image); - painter.setCompositionMode(QPainter::CompositionMode_Source); - painter.drawImage(damageRect, image, damageRect); - } else { - m_image = image; - m_image.detach(); - } - m_imageDevicePixelRatio = m_devicePixelRatio; - m_taskRunner->PostTask(FROM_HERE, base::BindOnce(std::move(m_swapCompletionCallback), toGfx(m_image.size()))); - m_taskRunner.reset(); + if (!m_swapCompletionCallback) + return; + + SkPixmap skPixmap; + surface_->peekPixels(&skPixmap); + QImage image(reinterpret_cast<const uchar *>(skPixmap.addr()), viewport_pixel_size_.width(), + viewport_pixel_size_.height(), skPixmap.rowBytes(), + imageFormat(skPixmap.colorType())); + if (m_image.size() == image.size()) { + QRect damageRect = toQt(damage_rect_); + QPainter painter(&m_image); + painter.setCompositionMode(QPainter::CompositionMode_Source); + painter.drawImage(damageRect, image, damageRect); + } else { + m_image = image; + m_image.detach(); } + m_imageDevicePixelRatio = m_devicePixelRatio; + m_taskRunner->PostTask( + FROM_HERE, base::BindOnce(std::move(m_swapCompletionCallback), toGfx(m_image.size()))); + m_taskRunner.reset(); +} - QSizeF sizeInDips = QSizeF(m_image.size()) / m_imageDevicePixelRatio; - node->setRect(QRectF(QPointF(0, 0), sizeInDips)); - node->setOwnsTexture(true); - node->setTexture(delegate->createTextureFromImage(m_image)); +QImage DisplaySoftwareOutputSurface::Device::image() +{ + return m_image; +} + +float DisplaySoftwareOutputSurface::Device::devicePixelRatio() +{ + return m_imageDevicePixelRatio; +} - return node; +QSize DisplaySoftwareOutputSurface::Device::size() +{ + return m_image.size(); +} + +bool DisplaySoftwareOutputSurface::Device::hasAlphaChannel() +{ + return m_image.format() == QImage::Format_ARGB32_Premultiplied; } DisplaySoftwareOutputSurface::DisplaySoftwareOutputSurface() diff --git a/src/core/config/common.pri b/src/core/config/common.pri index 9432fac7d..8ffd59e99 100644 --- a/src/core/config/common.pri +++ b/src/core/config/common.pri @@ -27,9 +27,10 @@ qtConfig(webengine-webrtc) { qtConfig(webengine-proprietary-codecs) { gn_args += proprietary_codecs=true ffmpeg_branding=\"Chrome\" - qtConfig(webengine-webrtc) { - gn_args += rtc_use_h264=true - } +# Fix after updating 3rdparty in dev to include the right fix +# qtConfig(webengine-webrtc) { +# gn_args += rtc_use_h264=true +# } } else { gn_args += proprietary_codecs=false } diff --git a/src/core/content_browser_client_qt.cpp b/src/core/content_browser_client_qt.cpp index d3181c555..4da4f72e4 100644 --- a/src/core/content_browser_client_qt.cpp +++ b/src/core/content_browser_client_qt.cpp @@ -109,10 +109,6 @@ #include "third_party/blink/public/mojom/insecure_input/insecure_input_service.mojom.h" #include "ui/base/resource/resource_bundle.h" #include "ui/base/ui_base_switches.h" -#include "ui/gl/gl_context.h" -#include "ui/gl/gl_implementation.h" -#include "ui/gl/gl_share_group.h" -#include "ui/gl/gpu_timing.h" #include "url/url_util_qt.h" #include "qtwebengine/common/renderer_configuration.mojom.h" @@ -122,7 +118,6 @@ #include "browser_main_parts_qt.h" #include "browser_message_filter_qt.h" #include "certificate_error_controller.h" -#include "certificate_error_controller_p.h" #include "client_cert_select_controller.h" #include "devtools_manager_delegate_qt.h" #include "login_delegate_qt.h" @@ -151,7 +146,7 @@ #include "api/qwebenginecookiestore.h" #include "api/qwebenginecookiestore_p.h" #include "api/qwebengineurlscheme.h" - +#include "ozone/gl_share_context_qt.h" #if defined(Q_OS_LINUX) #include "global_descriptors_qt.h" #include "ui/base/resource/resource_bundle.h" @@ -193,15 +188,6 @@ #include <QGuiApplication> #include <QLocale> #include <QStandardPaths> -#if QT_CONFIG(opengl) -# include <QOpenGLContext> -# include <QOpenGLExtraFunctions> -#endif -#include <qpa/qplatformnativeinterface.h> - -QT_BEGIN_NAMESPACE -Q_GUI_EXPORT QOpenGLContext *qt_gl_global_share_context(); -QT_END_NAMESPACE // Implement IsHandledProtocol as declared in //url/url_util_qt.h. namespace url { @@ -242,93 +228,6 @@ bool IsHandledProtocol(base::StringPiece scheme) namespace QtWebEngineCore { -class QtShareGLContext : public gl::GLContext { -public: - QtShareGLContext(QOpenGLContext *qtContext) - : gl::GLContext(0) - , m_handle(0) - { - QString platform = qApp->platformName().toLower(); - QPlatformNativeInterface *pni = QGuiApplication::platformNativeInterface(); - if (platform == QLatin1String("xcb") || platform == QLatin1String("offscreen")) { - if (gl::GetGLImplementation() == gl::kGLImplementationEGLGLES2) - m_handle = pni->nativeResourceForContext(QByteArrayLiteral("eglcontext"), qtContext); - else - m_handle = pni->nativeResourceForContext(QByteArrayLiteral("glxcontext"), qtContext); - } else if (platform == QLatin1String("cocoa")) - m_handle = pni->nativeResourceForContext(QByteArrayLiteral("cglcontextobj"), qtContext); - else if (platform == QLatin1String("qnx")) - m_handle = pni->nativeResourceForContext(QByteArrayLiteral("eglcontext"), qtContext); - else if (platform == QLatin1String("eglfs") || platform == QLatin1String("wayland") - || platform == QLatin1String("wayland-egl")) - m_handle = pni->nativeResourceForContext(QByteArrayLiteral("eglcontext"), qtContext); - else if (platform == QLatin1String("windows")) { - if (gl::GetGLImplementation() == gl::kGLImplementationEGLGLES2) - m_handle = pni->nativeResourceForContext(QByteArrayLiteral("eglContext"), qtContext); - else - m_handle = pni->nativeResourceForContext(QByteArrayLiteral("renderingcontext"), qtContext); - } else { - qFatal("%s platform not yet supported", platform.toLatin1().constData()); - // Add missing platforms once they work. - Q_UNREACHABLE(); - } - } - - void* GetHandle() override { return m_handle; } - unsigned int CheckStickyGraphicsResetStatus() override - { -#if QT_CONFIG(opengl) - if (QOpenGLContext *context = qt_gl_global_share_context()) { - if (context->format().testOption(QSurfaceFormat::ResetNotification)) - return context->extraFunctions()->glGetGraphicsResetStatus(); - } -#endif - return 0 /*GL_NO_ERROR*/; - } - - // We don't care about the rest, this context shouldn't be used except for its handle. - bool Initialize(gl::GLSurface *, const gl::GLContextAttribs &) override { Q_UNREACHABLE(); return false; } - bool MakeCurrent(gl::GLSurface *) override { Q_UNREACHABLE(); return false; } - void ReleaseCurrent(gl::GLSurface *) override { Q_UNREACHABLE(); } - bool IsCurrent(gl::GLSurface *) override { Q_UNREACHABLE(); return false; } - scoped_refptr<gl::GPUTimingClient> CreateGPUTimingClient() override - { - return nullptr; - } - const gfx::ExtensionSet& GetExtensions() override - { - static const gfx::ExtensionSet s_emptySet; - return s_emptySet; - } - void ResetExtensions() override - { - } - -private: - void *m_handle; -}; - -class ShareGroupQtQuick : public gl::GLShareGroup { -public: - gl::GLContext* GetContext() override { return m_shareContextQtQuick.get(); } - void AboutToAddFirstContext() override; - -private: - scoped_refptr<QtShareGLContext> m_shareContextQtQuick; -}; - -void ShareGroupQtQuick::AboutToAddFirstContext() -{ -#if QT_CONFIG(opengl) - // This currently has to be setup by ::main in all applications using QQuickWebEngineView with delegated rendering. - QOpenGLContext *shareContext = qt_gl_global_share_context(); - if (!shareContext) { - qFatal("QWebEngine: OpenGL resource sharing is not set up in QtQuick. Please make sure to call QtWebEngine::initialize() in your main() function before QCoreApplication is created."); - } - m_shareContextQtQuick = new QtShareGLContext(shareContext); -#endif -} - ContentBrowserClientQt::ContentBrowserClientQt() { } @@ -373,9 +272,9 @@ void ContentBrowserClientQt::RenderProcessWillLaunch(content::RenderProcessHost gl::GLShareGroup *ContentBrowserClientQt::GetInProcessGpuShareGroup() { - if (!m_shareGroupQtQuick.get()) - m_shareGroupQtQuick = new ShareGroupQtQuick; - return m_shareGroupQtQuick.get(); + if (!m_shareGroupQt.get()) + m_shareGroupQt = new ShareGroupQt; + return m_shareGroupQt.get(); } content::MediaObserver *ContentBrowserClientQt::GetMediaObserver() @@ -401,55 +300,18 @@ scoped_refptr<content::QuotaPermissionContext> ContentBrowserClientQt::CreateQuo return new QuotaPermissionContextQt; } -// Copied from chrome/browser/ssl/ssl_error_handler.cc: -static int IsCertErrorFatal(int cert_error) -{ - switch (cert_error) { - case net::ERR_CERT_COMMON_NAME_INVALID: - case net::ERR_CERT_DATE_INVALID: - case net::ERR_CERT_AUTHORITY_INVALID: - case net::ERR_CERT_NO_REVOCATION_MECHANISM: - case net::ERR_CERT_UNABLE_TO_CHECK_REVOCATION: - case net::ERR_CERT_WEAK_SIGNATURE_ALGORITHM: - case net::ERR_CERT_WEAK_KEY: - case net::ERR_CERT_NAME_CONSTRAINT_VIOLATION: - case net::ERR_CERT_VALIDITY_TOO_LONG: - case net::ERR_CERTIFICATE_TRANSPARENCY_REQUIRED: - case net::ERR_CERT_SYMANTEC_LEGACY: - case net::ERR_CERT_KNOWN_INTERCEPTION_BLOCKED: - case net::ERR_SSL_OBSOLETE_VERSION: - return false; - case net::ERR_CERT_CONTAINS_ERRORS: - case net::ERR_CERT_REVOKED: - case net::ERR_CERT_INVALID: - case net::ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN: - return true; - default: - NOTREACHED(); - } - return true; -} - void ContentBrowserClientQt::AllowCertificateError(content::WebContents *webContents, int cert_error, const net::SSLInfo &ssl_info, const GURL &request_url, - bool is_main_frame_request, + bool /* is_main_frame_request */, bool strict_enforcement, base::OnceCallback<void(content::CertificateRequestResultType)> callback) { WebContentsDelegateQt* contentsDelegate = static_cast<WebContentsDelegateQt*>(webContents->GetDelegate()); - QSharedPointer<CertificateErrorController> errorController( - new CertificateErrorController( - new CertificateErrorControllerPrivate( - cert_error, - ssl_info, - request_url, - is_main_frame_request, - IsCertErrorFatal(cert_error), - strict_enforcement, - std::move(callback)))); + QSharedPointer<CertificateErrorController> errorController(new CertificateErrorController( + cert_error, ssl_info, request_url, strict_enforcement, std::move(callback))); contentsDelegate->allowCertificateError(errorController); } @@ -1187,7 +1049,7 @@ void ContentBrowserClientQt::RegisterNonNetworkSubresourceURLLoaderFactories(int #endif if (!install_file_scheme && web_contents) { const auto *settings = static_cast<WebContentsDelegateQt *>(web_contents->GetDelegate())->webEngineSettings(); - if (settings->testAttribute(WebEngineSettings::LocalContentCanAccessFileUrls)) { + if (settings->testAttribute(QWebEngineSettings::LocalContentCanAccessFileUrls)) { for (const auto &local_scheme : url::GetLocalSchemes()) { if (url.SchemeIs(local_scheme)) { install_file_scheme = true; diff --git a/src/core/content_browser_client_qt.h b/src/core/content_browser_client_qt.h index fe6d8a076..876e6e529 100644 --- a/src/core/content_browser_client_qt.h +++ b/src/core/content_browser_client_qt.h @@ -76,7 +76,7 @@ namespace QtWebEngineCore { class BrowserMainPartsQt; class ProfileQt; -class ShareGroupQtQuick; +class ShareGroupQt; class ContentBrowserClientQt : public content::ContentBrowserClient { @@ -265,7 +265,7 @@ public: private: void InitFrameInterfaces(); - scoped_refptr<ShareGroupQtQuick> m_shareGroupQtQuick; + scoped_refptr<ShareGroupQt> m_shareGroupQt; std::unique_ptr<service_manager::BinderRegistry> m_frameInterfaces; std::unique_ptr<service_manager::BinderRegistryWithArgs<content::RenderFrameHost*>> m_frameInterfacesParameterized; }; diff --git a/src/core/core_chromium.pri b/src/core/core_chromium.pri index 836d30c0e..09ca86cfc 100644 --- a/src/core/core_chromium.pri +++ b/src/core/core_chromium.pri @@ -53,8 +53,8 @@ SOURCES = \ common/qt_ipc_logging.cpp \ common/qt_messages.cpp \ common/user_script_data.cpp \ + compositor/compositor.cpp \ compositor/content_gpu_client_qt.cpp \ - compositor/display_frame_sink.cpp \ compositor/display_overrides.cpp \ compositor/display_software_output_surface.cpp \ content_client_qt.cpp \ @@ -89,6 +89,7 @@ SOURCES = \ net/url_request_custom_job_proxy.cpp \ net/webui_controller_factory_qt.cpp \ ozone/gl_context_qt.cpp \ + ozone/gl_share_context_qt.cpp \ ozone/gl_ozone_egl_qt.cpp \ ozone/gl_surface_qt.cpp \ ozone/gl_surface_egl_qt.cpp \ @@ -108,6 +109,7 @@ SOURCES = \ register_protocol_handler_request_controller_impl.cpp \ render_view_context_menu_qt.cpp \ render_widget_host_view_qt.cpp \ + render_widget_host_view_qt_delegate_client.cpp \ renderer/content_renderer_client_qt.cpp \ renderer/content_settings_observer_qt.cpp \ renderer/render_frame_observer_qt.cpp \ @@ -146,7 +148,6 @@ HEADERS = \ browsing_data_remover_delegate_qt.h \ browser_main_parts_qt.h \ browser_message_filter_qt.h \ - certificate_error_controller_p.h \ certificate_error_controller.h \ client_cert_select_controller.h \ clipboard_change_observer.h \ @@ -156,8 +157,8 @@ HEADERS = \ color_chooser_controller.h \ common/qt_messages.h \ common/user_script_data.h \ + compositor/compositor.h \ compositor/content_gpu_client_qt.h \ - compositor/display_frame_sink.h \ compositor/display_software_output_surface.h \ content_client_qt.h \ content_browser_client_qt.h \ @@ -190,6 +191,7 @@ HEADERS = \ net/url_request_custom_job_proxy.h \ net/webui_controller_factory_qt.h \ ozone/gl_context_qt.h \ + ozone/gl_share_context_qt.h \ ozone/gl_ozone_egl_qt.h \ ozone/gl_surface_qt.h \ ozone/gl_surface_egl_qt.h \ @@ -214,6 +216,7 @@ HEADERS = \ render_view_context_menu_qt.h \ render_widget_host_view_qt.h \ render_widget_host_view_qt_delegate.h \ + render_widget_host_view_qt_delegate_client.h \ renderer/content_renderer_client_qt.h \ renderer/content_settings_observer_qt.h \ renderer/render_frame_observer_qt.h \ @@ -291,11 +294,11 @@ qtConfig(webengine-printing-and-pdf) { contains(QT_CONFIG, opengl) { SOURCES += \ compositor/compositor_resource_fence.cpp \ - compositor/display_gl_output_surface.cpp \ - compositor/display_gl_output_surface_qsg.cpp + compositor/display_gl_output_surface.cpp HEADERS += \ compositor/compositor_resource_fence.h \ compositor/display_gl_output_surface.h + macos { HEADERS+=macos_context_type_helper.h SOURCES+=macos_context_type_helper.mm diff --git a/src/core/doc/src/qwebenginesettings_lgpl.qdoc b/src/core/doc/src/qwebenginesettings_lgpl.qdoc new file mode 100644 index 000000000..a62abfbab --- /dev/null +++ b/src/core/doc/src/qwebenginesettings_lgpl.qdoc @@ -0,0 +1,301 @@ +/* + Copyright (C) 2015 The Qt Company Ltd. + Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +// The documentation in this file was imported from QtWebKit and is thus constrained +// by its LGPL license. Documentation written from scratch for new methods should be +// placed inline in the code as usual. + +/*! + \class QWebEngineSettings + \since 5.4 + \brief The QWebEngineSettings class provides an object to store the settings used + by QWebEnginePage. + + \inmodule QtWebEngineCore + + QWebEngineSettings allows configuration of browser properties, such as font sizes and + families, the location of a custom style sheet, and generic attributes, such as JavaScript + support. Individual attributes are set using the setAttribute() function. The + \l{QWebEngineSettings::WebAttribute}{WebAttribute} enum further describes each attribute. + + Each QWebEnginePage object has its own QWebEngineSettings object, which configures the + settings for that page. If a setting is not configured for a web engine + page, it is looked up in the settings of the profile the page belongs to. + + \sa QWebEnginePage::settings(), QWebEngineView::settings() +*/ + +/*! + \enum QWebEngineSettings::FontFamily + + This enum describes the generic font families defined by CSS 2. + For more information see the + \l{http://www.w3.org/TR/REC-CSS2/fonts.html#generic-font-families}{CSS standard}. + + \value StandardFont + \value FixedFont + \value SerifFont + \value SansSerifFont + \value CursiveFont + \value FantasyFont + \value PictographFont + (added in Qt 5.7) +*/ + +/*! + \enum QWebEngineSettings::FontSize + + This enum describes the font sizes configurable through QWebEngineSettings: + + \value MinimumFontSize The hard minimum font size. + \value MinimumLogicalFontSize The minimum logical font size that is applied + when zooming out. + \value DefaultFontSize The default font size for regular text. + \value DefaultFixedFontSize The default font size for fixed-pitch text. +*/ + +/*! + \enum QWebEngineSettings::WebAttribute + + This enum type specifies settings for web pages: + + \value AutoLoadImages + Automatically dowloads images for web pages. When this setting is + disabled, images are loaded from the cache. Enabled by default. + \value JavascriptEnabled + Enables the running of JavaScript programs in the + \l{QWebEngineScript::MainWorld}{MainWorld}. Enabled by default. + \value JavascriptCanOpenWindows + Allows JavaScript programs to open popup windows without user + interaction. Enabled by default. + \value JavascriptCanAccessClipboard + Allows JavaScript programs to read from and write to the clipboard. + Writing to the clipboard is always allowed if it is specifically requested by the user. + See JavascriptCanPaste to also allow pasting the content of the clipboard content from + JavaScript. + Disabled by default. + \value LinksIncludedInFocusChain + Includes hyperlinks in the keyboard focus chain. Enabled by default. + \value LocalStorageEnabled + Enables support for the HTML 5 local storage feature. Enabled by default. + \value LocalContentCanAccessRemoteUrls + Allows locally loaded documents to ignore cross-origin rules so that they can access + remote resources that would normally be blocked, because all remote resources are + considered cross-origin for a local file. Remote access that would not be blocked by + cross-origin rules is still possible when this setting is disabled (default). + Note that disabling this setting does not stop XMLHttpRequests or media elements in + local files from accessing remote content. Basically, it only stops some HTML + subresources, such as scripts, and therefore disabling this setting is not a safety + mechanism. + \value XSSAuditingEnabled + Obsolete and has no effect. + \value SpatialNavigationEnabled + Enables the Spatial Navigation feature, which means the ability to navigate between + focusable elements, such as hyperlinks and form controls, on a web page by using the + Left, Right, Up and Down arrow keys. For example, if a user presses the + Right key, heuristics determine whether there is an element they might be + trying to reach towards the right and which element they probably want. + Disabled by default. + \value LocalContentCanAccessFileUrls + Allows locally loaded documents to access other local URLs. Enabled by default. + \value HyperlinkAuditingEnabled + Enables support for the \c ping attribute for hyperlinks. Disabled by default. + \value ScrollAnimatorEnabled + Enables animated scrolling. Disabled by default. + \value ErrorPageEnabled + Enables displaying the built-in error pages of Chromium. Enabled by default. + \value PluginsEnabled + Enables support for Pepper plugins, such as the Flash player. Disabled by default. + See also \l{Pepper Plugin API}. (Added in Qt 5.6) + \value FullScreenSupportEnabled + Enables fullscreen support in an application. Disabled by default. (Added in Qt 5.6) + \value ScreenCaptureEnabled + Enables screen capture in an application. Disabled by default. (Added in Qt 5.7) + \value WebGLEnabled + Enables support for HTML 5 WebGL. Enabled by default if available. (Added in Qt 5.7) + \value Accelerated2dCanvasEnabled + Specifies whether the HTML5 2D canvas should be a OpenGL framebuffer. + This makes many painting operations faster, but slows down pixel access. Enabled by default if available. (Added in Qt 5.7) + \value AutoLoadIconsForPage + Automatically downloads icons for web pages. Enabled by default. (Added in Qt 5.7) + \value TouchIconsEnabled + Enables support for touch icons and precomposed touch icons + Disabled by default. (Added in Qt 5.7) + \value FocusOnNavigationEnabled + Gives focus to the view associated with the page, whenever a navigation operation occurs + (load, stop, reload, reload and bypass cache, forward, backward, set content, and so + on). + Disabled by default. (Added in Qt 5.8) + \value PrintElementBackgrounds + Turns on printing of CSS backgrounds when printing a web page. + Enabled by default. (Added in Qt 5.8) + \value AllowRunningInsecureContent + By default, HTTPS pages cannot run JavaScript, CSS, plugins or + web-sockets from HTTP URLs. This provides an override to get + the old insecure behavior. + Disabled by default. (Added in Qt 5.8) + \value AllowGeolocationOnInsecureOrigins + Since Qt 5.7, only secure origins such as HTTPS have been able to request + Geolocation features. This provides an override to allow non secure + origins to access Geolocation again. + Disabled by default. (Added in Qt 5.9) + \value AllowWindowActivationFromJavaScript + Allows activating windows by using the window.focus() JavaScript + method. Disabled by default. + (Added in Qt 5.10) + \value ShowScrollBars + Shows scroll bars. + Enabled by default. (Added in Qt 5.10) + \value PlaybackRequiresUserGesture + Inhibits playback of media content until the user interacts with + the page. By default, WebEngine uses Chromium settings, as described + in \l {Autoplay Policy Changes}. This is similar to how Chrome on + Android behaves, while the default behavior when it is disabled is + similar to Chrome on desktops. To overwrite the default behavior, + disable this setting. (Added in Qt 5.11) + \value JavascriptCanPaste + Enables JavaScript \c{execCommand("paste")}. This also requires + enabling JavascriptCanAccessClipboard. + Disabled by default. (Added in Qt 5.11) + \value WebRTCPublicInterfacesOnly + Limits WebRTC to public IP addresses only. When disabled WebRTC may also use + local network IP addresses, but remote hosts can also see your local network + IP address. + Disabled by default. (Added in Qt 5.11) + \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) +*/ + +/*! + \enum QWebEngineSettings::UnknownUrlSchemePolicy + \since Qt 5.11 + + This enum describes how navigation requests to URLs with unknown schemes are handled. + + \value DisallowUnknownUrlSchemes + Disallows all navigation requests to URLs with unknown schemes. + \value AllowUnknownUrlSchemesFromUserInteraction + Allows navigation requests to URLs with unknown schemes that are issued from + user-interaction (like a mouse-click), whereas other navigation requests (for example + from JavaScript) are suppressed. + \value AllowAllUnknownUrlSchemes + Allows all navigation requests to URLs with unknown schemes. + + \sa unknownUrlSchemePolicy setUnknownUrlSchemePolicy resetUnknownUrlSchemePolicy +*/ + +/*! + \fn void QWebEngineSettings::setFontSize(FontSize type, int size) + Sets the font size for \a type to \a size in pixels. +*/ + +/*! + \fn int QWebEngineSettings::fontSize(FontSize type) const + Returns the default font size for \a type in pixels. +*/ + +/*! + \fn void QWebEngineSettings::resetFontSize(FontSize type) + Resets the font size for \a type to the size specified in the profile that + the page belongs to. +*/ + +/*! + \fn void QWebEngineSettings::setDefaultTextEncoding(const QString& encoding) + Specifies the default text encoding system. + + The value of \a encoding must be a string describing an encoding such as "utf-8" or + "iso-8859-1". If left empty, a default value will be used. For a more + extensive list of encoding names see \l{QTextCodec}. + + \sa defaultTextEncoding() +*/ + +/*! + \fn QString QWebEngineSettings::defaultTextEncoding() const + Returns the default text encoding. + + \sa setDefaultTextEncoding() +*/ + +/*! + \fn void QWebEngineSettings::setFontFamily(FontFamily which, const QString& family) + Sets the actual font family to \a family for the specified generic family, + \a which. +*/ + +/*! + \fn QString QWebEngineSettings::fontFamily(FontFamily which) const + Returns the actual font family for the specified generic font family, + \a which. +*/ + +/*! + \fn void QWebEngineSettings::resetFontFamily(FontFamily which) + Resets the actual font family specified by \a which to the one specified + in the profile that the page belongs to. +*/ + +/*! + \fn QWebEngineSettings::UnknownUrlSchemePolicy QWebEngineSettings::unknownUrlSchemePolicy() const + \since Qt 5.11 + Returns the currently selected policy for handling navigation requests to URLs with + unknown schemes. Default is \l{QWebEngineSettings::AllowUnknownUrlSchemesFromUserInteraction}. + \sa setUnknownUrlSchemePolicy resetUnknownUrlSchemePolicy +*/ + +/*! + \fn void QWebEngineSettings::setUnknownUrlSchemePolicy(QWebEngineSettings::UnknownUrlSchemePolicy policy) + \since Qt 5.11 + Sets the policy for handling navigation requests to URLs with unknown schemes to \a policy. + Default is \l{QWebEngineSettings::AllowUnknownUrlSchemesFromUserInteraction}. + \sa unknownUrlSchemePolicy resetUnknownUrlSchemePolicy +*/ + +/*! + \fn void QWebEngineSettings::resetUnknownUrlSchemePolicy() + \since Qt 5.11 + Removes the policy for handling navigation requests to URLs with unknown schemes. + \sa unknownUrlSchemePolicy setUnknownUrlSchemePolicy +*/ + +/*! + \fn void QWebEngineSettings::setAttribute(WebAttribute attribute, bool on) + + Enables or disables the specified \a attribute feature depending on the + value of \a on. +*/ + +/*! + \fn bool QWebEngineSettings::testAttribute(WebAttribute attribute) const + + Returns \c true if \a attribute is enabled; otherwise returns \c false. +*/ + +/*! + \fn void QWebEngineSettings::resetAttribute(WebAttribute attribute) + + Resets the setting of \a attribute to the value specified in the + profile that the page belongs to. +*/ diff --git a/src/core/download_manager_delegate_qt.cpp b/src/core/download_manager_delegate_qt.cpp index b3c0c7c07..3760ebb49 100644 --- a/src/core/download_manager_delegate_qt.cpp +++ b/src/core/download_manager_delegate_qt.cpp @@ -68,7 +68,6 @@ DownloadManagerDelegateQt::DownloadManagerDelegateQt(ProfileAdapter *profileAdap : m_profileAdapter(profileAdapter) , m_currentId(0) , m_weakPtrFactory(this) - , m_nextDownloadIsUserRequested(false) { Q_ASSERT(m_profileAdapter); } @@ -142,17 +141,6 @@ bool DownloadManagerDelegateQt::DetermineDownloadTarget(download::DownloadItem * QString suggestedFilename = toQt(item->GetSuggestedFilename()); QString mimeTypeString = toQt(item->GetMimeType()); - int downloadType = 0; - if (m_nextDownloadIsUserRequested) { - downloadType = ProfileAdapterClient::UserRequested; - m_nextDownloadIsUserRequested = false; - } else { - bool isAttachment = net::HttpContentDisposition(item->GetContentDisposition(), std::string()).is_attachment(); - if (isAttachment) - downloadType = ProfileAdapterClient::Attachment; - else - downloadType = ProfileAdapterClient::DownloadAttribute; - } if (suggestedFilename.isEmpty()) suggestedFilename = toQt(net::HttpContentDisposition(item->GetContentDisposition(), net::kCharsetLatin1).filename()); @@ -195,7 +183,7 @@ bool DownloadManagerDelegateQt::DetermineDownloadTarget(download::DownloadItem * false /* accepted */, false /* paused */, false /* done */, - downloadType, + false /* isSavePageDownload */, item->GetLastReason(), adapterClient, suggestedFilename, @@ -297,7 +285,7 @@ void DownloadManagerDelegateQt::ChooseSavePath(content::WebContents *web_content acceptedByDefault, false, /* paused */ false, /* done */ - ProfileAdapterClient::SavePage, + true, /* isSavePageDownload */ ProfileAdapterClient::NoReason, adapterClient, QFileInfo(suggestedFilePath).fileName(), diff --git a/src/core/download_manager_delegate_qt.h b/src/core/download_manager_delegate_qt.h index 7f4f33702..eda1e4f21 100644 --- a/src/core/download_manager_delegate_qt.h +++ b/src/core/download_manager_delegate_qt.h @@ -89,8 +89,6 @@ public: void resumeDownload(quint32 downloadId); void removeDownload(quint32 downloadId); - void markNextDownloadAsUserRequested() { m_nextDownloadIsUserRequested = true; } - // Inherited from content::DownloadItem::Observer void OnDownloadUpdated(download::DownloadItem *download) override; void OnDownloadDestroyed(download::DownloadItem *download) override; @@ -103,7 +101,6 @@ private: uint32_t m_currentId; base::WeakPtrFactory<DownloadManagerDelegateQt> m_weakPtrFactory; - bool m_nextDownloadIsUserRequested; friend class DownloadManagerDelegateInstance; friend class ProfileAdapter; diff --git a/src/core/favicon_manager.cpp b/src/core/favicon_manager.cpp index 4496606f9..3cb417c4f 100644 --- a/src/core/favicon_manager.cpp +++ b/src/core/favicon_manager.cpp @@ -192,8 +192,8 @@ void FaviconManager::storeIcon(int id, const QIcon &icon) m_inProgressRequests.remove(id); if (m_inProgressRequests.isEmpty()) { - WebEngineSettings *settings = m_viewClient->webEngineSettings(); - bool touchIconsEnabled = settings->testAttribute(WebEngineSettings::TouchIconsEnabled); + QWebEngineSettings *settings = m_viewClient->webEngineSettings(); + bool touchIconsEnabled = settings->testAttribute(QWebEngineSettings::TouchIconsEnabled); generateCandidateIcon(touchIconsEnabled); const QUrl &iconUrl = candidateIconUrl(touchIconsEnabled); @@ -248,13 +248,13 @@ void FaviconManager::update(const QList<FaviconInfo> &candidates) { updateCandidates(candidates); - WebEngineSettings *settings = m_viewClient->webEngineSettings(); - if (!settings->testAttribute(WebEngineSettings::AutoLoadIconsForPage)) { + QWebEngineSettings *settings = m_viewClient->webEngineSettings(); + if (!settings->testAttribute(QWebEngineSettings::AutoLoadIconsForPage)) { m_viewClient->iconChanged(QUrl()); return; } - bool touchIconsEnabled = settings->testAttribute(WebEngineSettings::TouchIconsEnabled); + bool touchIconsEnabled = settings->testAttribute(QWebEngineSettings::TouchIconsEnabled); const QList<FaviconInfo> &faviconInfoList = getFaviconInfoList(true /* candidates only */); for (auto it = faviconInfoList.cbegin(), end = faviconInfoList.cend(); it != end; ++it) { diff --git a/src/core/gn_run.pro b/src/core/gn_run.pro index 3d6fda80e..4688ea59d 100644 --- a/src/core/gn_run.pro +++ b/src/core/gn_run.pro @@ -7,11 +7,7 @@ TEMPLATE = aux qtConfig(debug_and_release): CONFIG += debug_and_release qtConfig(build_all): CONFIG += build_all -qtConfig(webengine-system-ninja) { - QT_TOOL.ninja.binary = ninja -} else { - QT_TOOL.ninja.binary = $$shell_quote($$shell_path($$ninjaPath())) -} +QT_TOOL.ninja.binary = $$shell_quote($$shell_path($$ninjaPath())) win32 { # Add the gnuwin32/bin subdir of qt5.git to PATH. Needed for calling bison and friends. diff --git a/src/core/macos_context_type_helper.h b/src/core/macos_context_type_helper.h index d234a2bff..a7b989bc3 100644 --- a/src/core/macos_context_type_helper.h +++ b/src/core/macos_context_type_helper.h @@ -39,4 +39,5 @@ #ifndef MACOS_CONTEXT_TYPE_HELPER_H_ #define MACOS_CONTEXT_TYPE_HELPER_H_ bool isCurrentContextSoftware(); +void* cglContext(NSOpenGLContext*); #endif // MACOS_CONTEXT_TYPE_HELPER_H_ diff --git a/src/core/macos_context_type_helper.mm b/src/core/macos_context_type_helper.mm index c814d2849..4c9302482 100644 --- a/src/core/macos_context_type_helper.mm +++ b/src/core/macos_context_type_helper.mm @@ -47,3 +47,8 @@ bool isCurrentContextSoftware() [NSOpenGLContext.currentContext getValues:&rendererID forParameter:NSOpenGLContextParameterCurrentRendererID]; return (rendererID & kCGLRendererIDMatchingMask) == kCGLRendererGenericFloatID; } + +void* cglContext(NSOpenGLContext *nsOpenGLContext) +{ + return [nsOpenGLContext CGLContextObj]; +} diff --git a/src/core/media_capture_devices_dispatcher.cpp b/src/core/media_capture_devices_dispatcher.cpp index 693cfa2e3..62d218625 100644 --- a/src/core/media_capture_devices_dispatcher.cpp +++ b/src/core/media_capture_devices_dispatcher.cpp @@ -337,8 +337,8 @@ void MediaCaptureDevicesDispatcher::processMediaAccessRequest(WebContentsAdapter } if (flags.testFlag(WebContentsAdapterClient::MediaDesktopVideoCapture)) { - const bool screenCaptureEnabled = - adapterClient->webEngineSettings()->testAttribute(WebEngineSettings::ScreenCaptureEnabled); + const bool screenCaptureEnabled = adapterClient->webEngineSettings()->testAttribute( + QWebEngineSettings::ScreenCaptureEnabled); const bool originIsSecure = content::IsOriginSecure(request.security_origin); if (!screenCaptureEnabled || !originIsSecure) { std::move(callback).Run(blink::MediaStreamDevices(), MediaStreamRequestResult::INVALID_STATE, std::unique_ptr<content::MediaStreamUI>()); diff --git a/src/core/net/client_cert_store_data.h b/src/core/net/client_cert_store_data.h index e47a909e4..4976ac936 100644 --- a/src/core/net/client_cert_store_data.h +++ b/src/core/net/client_cert_store_data.h @@ -46,7 +46,7 @@ #if QT_CONFIG(ssl) #include "base/memory/ref_counted.h" -#include <QtCore/qvector.h> +#include <QtCore/qlist.h> #include <QtNetwork/qsslcertificate.h> #include <QtNetwork/qsslkey.h> @@ -71,7 +71,7 @@ struct ClientCertificateStoreData void remove(const QSslCertificate &certificate); void clear(); - QVector<Entry *> extraCerts; + QList<Entry *> extraCerts; }; } // namespace QtWebEngineCore diff --git a/src/core/net/cookie_monster_delegate_qt.h b/src/core/net/cookie_monster_delegate_qt.h index 748e92da9..a8432e125 100644 --- a/src/core/net/cookie_monster_delegate_qt.h +++ b/src/core/net/cookie_monster_delegate_qt.h @@ -53,11 +53,6 @@ #include "qtwebenginecoreglobal_p.h" -QT_WARNING_PUSH -// For some reason adding -Wno-unused-parameter to QMAKE_CXXFLAGS has no -// effect with clang, so use a pragma for these dirty chromium headers -QT_WARNING_DISABLE_CLANG("-Wunused-parameter") - // We need to work around Chromium using 'signals' as a variable name in headers: #ifdef signals #define StAsH_signals signals @@ -73,7 +68,6 @@ QT_WARNING_DISABLE_CLANG("-Wunused-parameter") #define signals StAsH_signals #undef StAsH_signals #endif -QT_WARNING_POP #include <QNetworkCookie> #include <QPointer> diff --git a/src/core/net/plugin_response_interceptor_url_loader_throttle.cpp b/src/core/net/plugin_response_interceptor_url_loader_throttle.cpp index 4641717f7..f6bddd7b2 100644 --- a/src/core/net/plugin_response_interceptor_url_loader_throttle.cpp +++ b/src/core/net/plugin_response_interceptor_url_loader_throttle.cpp @@ -70,8 +70,8 @@ void onPdfStreamIntercepted(const GURL &original_url, std::string extension_id, return; WebEngineSettings *settings = contentsDelegate->webEngineSettings(); - if (!settings->testAttribute(WebEngineSettings::PdfViewerEnabled) - || !settings->testAttribute(WebEngineSettings::PluginsEnabled)) { + if (!settings->testAttribute(QWebEngineSettings::PdfViewerEnabled) + || !settings->testAttribute(QWebEngineSettings::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( diff --git a/src/core/ozone/gl_context_qt.cpp b/src/core/ozone/gl_context_qt.cpp index 9a24f6bf4..e511e8eb5 100644 --- a/src/core/ozone/gl_context_qt.cpp +++ b/src/core/ozone/gl_context_qt.cpp @@ -173,6 +173,24 @@ QFunctionPointer GLContextHelper::getEglGetProcAddress() return get_proc_address; } +void *GLContextHelper::getGlxPlatformInterface() +{ +#if QT_CONFIG(opengl) && defined(USE_GLX) + if (QOpenGLContext *context = qt_gl_global_share_context()) + return context->platformInterface<QPlatformInterface::QGLXContext>(); +#endif + return nullptr; +} + +void *GLContextHelper::getEglPlatformInterface() +{ +#if QT_CONFIG(opengl) && QT_CONFIG(egl) + if (QOpenGLContext *context = qt_gl_global_share_context()) + return context->platformInterface<QPlatformInterface::QEGLContext>(); +#endif + return nullptr; +} + bool GLContextHelper::isCreateContextRobustnessSupported() { return contextHelper->m_robustness; diff --git a/src/core/ozone/gl_context_qt.h b/src/core/ozone/gl_context_qt.h index cc4f6b0d1..612aae3f5 100644 --- a/src/core/ozone/gl_context_qt.h +++ b/src/core/ozone/gl_context_qt.h @@ -65,6 +65,8 @@ public: static QFunctionPointer getGlXGetProcAddress(); static QFunctionPointer getEglGetProcAddress(); static bool isCreateContextRobustnessSupported(); + static void *getGlxPlatformInterface(); + static void *getEglPlatformInterface(); private: Q_INVOKABLE bool initializeContextOnBrowserThread(gl::GLContext* context, gl::GLSurface* surface, gl::GLContextAttribs attribs); diff --git a/src/core/ozone/gl_ozone_egl_qt.cpp b/src/core/ozone/gl_ozone_egl_qt.cpp index c33570d44..a8b7cdfe4 100644 --- a/src/core/ozone/gl_ozone_egl_qt.cpp +++ b/src/core/ozone/gl_ozone_egl_qt.cpp @@ -38,19 +38,10 @@ ****************************************************************************/ #if defined(USE_OZONE) -#include <QtCore/qobject.h> -#include <QtGui/qtgui-config.h> - -#if QT_CONFIG(opengl) -#include <QOpenGLContext> -QT_BEGIN_NAMESPACE -Q_GUI_EXPORT QOpenGLContext *qt_gl_global_share_context(); -QT_END_NAMESPACE -#endif - #include "gl_context_qt.h" #include "gl_ozone_egl_qt.h" #include "gl_surface_egl_qt.h" + #include "base/files/file_path.h" #include "base/native_library.h" #include "ui/gl/gl_context_egl.h" @@ -59,7 +50,6 @@ QT_END_NAMESPACE #include "ui/gl/init/gl_factory.h" #include "ui/gl/init/gl_initializer.h" - #include <EGL/egl.h> #include <dlfcn.h> @@ -87,15 +77,11 @@ bool GLOzoneEGLQt::LoadGLES2Bindings(gl::GLImplementation /*implementation*/) reinterpret_cast<gl::GLGetProcAddressProc>( base::GetFunctionPointerFromNativeLibrary(eglgles2Library, "eglGetProcAddress")); -#if QT_CONFIG(opengl) if (!get_proc_address) { // QTBUG-63341 most likely libgles2 not linked with libegl -> fallback to qpa - if (QOpenGLContext *context = qt_gl_global_share_context()) { - get_proc_address = reinterpret_cast<gl::GLGetProcAddressProc>( - context->getProcAddress("eglGetProcAddress")); - } + QFunctionPointer address = GLContextHelper::getEglGetProcAddress(); + get_proc_address = reinterpret_cast<gl::GLGetProcAddressProc>(address); } -#endif if (!get_proc_address) { LOG(ERROR) << "eglGetProcAddress not found."; diff --git a/src/core/ozone/gl_share_context_qt.cpp b/src/core/ozone/gl_share_context_qt.cpp new file mode 100644 index 000000000..669652057 --- /dev/null +++ b/src/core/ozone/gl_share_context_qt.cpp @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** Copyright (C) 2020 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 "gl_share_context_qt.h" +#include <QtGui/qtgui-config.h> +#include <qpa/qplatformnativeinterface.h> +#include <QtGui/qopenglcontext_platform.h> +#if defined(Q_OS_MACOS) +#include "macos_context_type_helper.h" +#endif +#if QT_CONFIG(opengl) +#include <QOpenGLContext> +#include <QOpenGLExtraFunctions> +#endif + +namespace QtWebEngineCore { + +QtShareGLContext::QtShareGLContext(QOpenGLContext *qtContext) + : gl::GLContext(nullptr), m_handle(nullptr) +{ +#if QT_CONFIG(opengl) + QOpenGLContext *context = QOpenGLContext::globalShareContext(); +#if defined(Q_OS_MACOS) + auto *ctx = context->platformInterface<QPlatformInterface::QCocoaGLContext>(); + if (ctx) + m_handle = cglContext(ctx->nativeContext()); +#endif +#if defined(Q_OS_WIN) + auto *ctx = context->platformInterface<QPlatformInterface::QWGLContext>(); +#endif +#if defined(Q_OS_LINUX) + auto *ctx = context->platformInterface<QPlatformInterface::QGLXContext>(); +#endif + if (ctx && !m_handle) + m_handle = (void *)ctx->nativeContext(); +#if QT_CONFIG(egl) + if (!m_handle) { + auto *ctx = context->platformInterface<QPlatformInterface::QEGLContext>(); + if (ctx) + m_handle = (void *)ctx->nativeContext(); + } +#endif + if (!m_handle) + qFatal("Could not get handle for shared contex"); +#endif // QT_CONFIG(opengl) +} + +unsigned int QtShareGLContext::CheckStickyGraphicsResetStatus() +{ +#if QT_CONFIG(opengl) + if (QOpenGLContext *context = QOpenGLContext::globalShareContext()) { + if (context->format().testOption(QSurfaceFormat::ResetNotification)) + return context->extraFunctions()->glGetGraphicsResetStatus(); + } +#endif + return 0 /*GL_NO_ERROR*/; +} + +void ShareGroupQt::AboutToAddFirstContext() +{ +#if QT_CONFIG(opengl) + // This currently has to be setup by ::main in all applications using QQuickWebEngineView with + // delegated rendering. + QOpenGLContext *shareContext = QOpenGLContext::globalShareContext(); + if (!shareContext) { + qFatal("QWebEngine: OpenGL resource sharing is not set up in QtQuick. Please make sure to " + "call QtWebEngine::initialize() in your main() function before QCoreApplication is " + "created."); + } + m_shareContextQt = new QtShareGLContext(shareContext); +#endif +} + +} // namespace diff --git a/src/core/ozone/gl_share_context_qt.h b/src/core/ozone/gl_share_context_qt.h new file mode 100644 index 000000000..26e884e10 --- /dev/null +++ b/src/core/ozone/gl_share_context_qt.h @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2020 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 GL_SHARE_CONTEXT_QT +#define GL_SHARE_CONTEXT_QT + +#include "ui/gl/gpu_timing.h" +#include "ui/gl/gl_context.h" +#include "ui/gl/gl_share_group.h" +#include "qtwebenginecoreglobal.h" + +QT_FORWARD_DECLARE_CLASS(QOpenGLContext) + +namespace QtWebEngineCore { + +class QtShareGLContext : public gl::GLContext +{ + +public: + QtShareGLContext(QOpenGLContext *qtContext); + void *GetHandle() override { return m_handle; } + unsigned int CheckStickyGraphicsResetStatus() override; + // We don't care about the rest, this context shouldn't be used except for its handle. + bool Initialize(gl::GLSurface *, const gl::GLContextAttribs &) override + { + Q_UNREACHABLE(); + return false; + } + bool MakeCurrent(gl::GLSurface *) override + { + Q_UNREACHABLE(); + return false; + } + void ReleaseCurrent(gl::GLSurface *) override { Q_UNREACHABLE(); } + bool IsCurrent(gl::GLSurface *) override + { + Q_UNREACHABLE(); + return false; + } + scoped_refptr<gl::GPUTimingClient> CreateGPUTimingClient() override { return nullptr; } + const gfx::ExtensionSet &GetExtensions() override + { + static const gfx::ExtensionSet s_emptySet; + return s_emptySet; + } + void ResetExtensions() override {} + +private: + void *m_handle; +}; + +class ShareGroupQt : public gl::GLShareGroup +{ + +public: + gl::GLContext *GetContext() override { return m_shareContextQt.get(); } + void AboutToAddFirstContext() override; + +private: + scoped_refptr<QtShareGLContext> m_shareContextQt; +}; +} // namespace +#endif diff --git a/src/core/ozone/surface_factory_qt.cpp b/src/core/ozone/surface_factory_qt.cpp index 12b997148..846d930d6 100644 --- a/src/core/ozone/surface_factory_qt.cpp +++ b/src/core/ozone/surface_factory_qt.cpp @@ -51,13 +51,13 @@ namespace QtWebEngineCore { SurfaceFactoryQt::SurfaceFactoryQt() { #if defined(USE_GLX) - if (GLContextHelper::getGlXConfig()) { - m_impl = gl::kGLImplementationDesktopGL; + if (GLContextHelper::getGlxPlatformInterface()) { + m_impl = { gl::kGLImplementationDesktopGL }; m_ozone.reset(new ui::GLOzoneGLXQt()); } else #endif - if (GLContextHelper::getEGLConfig()) { - m_impl = gl::kGLImplementationEGLGLES2; + if (GLContextHelper::getEglPlatformInterface()) { + m_impl = { gl::kGLImplementationDesktopGL, gl::kGLImplementationEGLGLES2 }; m_ozone.reset(new ui::GLOzoneEGLQt()); } else { qFatal("No suitable graphics backend found\n"); @@ -66,7 +66,7 @@ SurfaceFactoryQt::SurfaceFactoryQt() std::vector<gl::GLImplementation> SurfaceFactoryQt::GetAllowedGLImplementations() { - return { m_impl }; + return m_impl; } ui::GLOzone* SurfaceFactoryQt::GetGLOzone(gl::GLImplementation implementation) diff --git a/src/core/ozone/surface_factory_qt.h b/src/core/ozone/surface_factory_qt.h index dee41d948..232f11e0f 100644 --- a/src/core/ozone/surface_factory_qt.h +++ b/src/core/ozone/surface_factory_qt.h @@ -53,7 +53,7 @@ public: std::vector<gl::GLImplementation> GetAllowedGLImplementations() override; ui::GLOzone* GetGLOzone(gl::GLImplementation implementation) override; private: - gl::GLImplementation m_impl; + std::vector<gl::GLImplementation> m_impl; std::unique_ptr<ui::GLOzone> m_ozone; }; diff --git a/src/core/permission_manager_qt.cpp b/src/core/permission_manager_qt.cpp index a1b481946..8b9eab3eb 100644 --- a/src/core/permission_manager_qt.cpp +++ b/src/core/permission_manager_qt.cpp @@ -215,8 +215,8 @@ int PermissionManagerQt::RequestPermission(content::PermissionType permission, ProfileAdapter::PermissionType permissionType = toQt(permission); if (permissionType == ProfileAdapter::ClipboardRead) { WebEngineSettings *settings = contentsDelegate->webEngineSettings(); - if (settings->testAttribute(WebEngineSettings::JavascriptCanAccessClipboard) - && settings->testAttribute(WebEngineSettings::JavascriptCanPaste)) + if (settings->testAttribute(QWebEngineSettings::JavascriptCanAccessClipboard) + && settings->testAttribute(QWebEngineSettings::JavascriptCanPaste)) std::move(callback).Run(blink::mojom::PermissionStatus::GRANTED); else std::move(callback).Run(blink::mojom::PermissionStatus::DENIED); @@ -257,8 +257,8 @@ int PermissionManagerQt::RequestPermissions(const std::vector<content::Permissio result.push_back(blink::mojom::PermissionStatus::DENIED); else if (permissionType == ProfileAdapter::ClipboardRead) { WebEngineSettings *settings = contentsDelegate->webEngineSettings(); - if (settings->testAttribute(WebEngineSettings::JavascriptCanAccessClipboard) - && settings->testAttribute(WebEngineSettings::JavascriptCanPaste)) + if (settings->testAttribute(QWebEngineSettings::JavascriptCanAccessClipboard) + && settings->testAttribute(QWebEngineSettings::JavascriptCanPaste)) result.push_back(blink::mojom::PermissionStatus::GRANTED); else result.push_back(blink::mojom::PermissionStatus::DENIED); @@ -309,10 +309,12 @@ blink::mojom::PermissionStatus PermissionManagerQt::GetPermissionStatusForFrame( permission == content::PermissionType::CLIPBOARD_SANITIZED_WRITE) { WebContentsDelegateQt *delegate = static_cast<WebContentsDelegateQt *>( content::WebContents::FromRenderFrameHost(render_frame_host)->GetDelegate()); - if (!delegate->webEngineSettings()->testAttribute(WebEngineSettings::JavascriptCanAccessClipboard)) + if (!delegate->webEngineSettings()->testAttribute( + QWebEngineSettings::JavascriptCanAccessClipboard)) return blink::mojom::PermissionStatus::DENIED; - if (permission == content::PermissionType::CLIPBOARD_READ_WRITE && - !delegate->webEngineSettings()->testAttribute(WebEngineSettings::JavascriptCanPaste)) + if (permission == content::PermissionType::CLIPBOARD_READ_WRITE + && !delegate->webEngineSettings()->testAttribute( + QWebEngineSettings::JavascriptCanPaste)) return blink::mojom::PermissionStatus::DENIED; return blink::mojom::PermissionStatus::GRANTED; } diff --git a/src/core/pref_service_adapter.h b/src/core/pref_service_adapter.h index 1c7c44a96..93a61302f 100644 --- a/src/core/pref_service_adapter.h +++ b/src/core/pref_service_adapter.h @@ -44,12 +44,6 @@ #include "components/prefs/pref_service.h" #include "qtwebenginecoreglobal_p.h" -QT_BEGIN_NAMESPACE -class QStringList; -QT_END_NAMESPACE - -class ProfileAdapter; - namespace QtWebEngineCore { class ProfileAdapter; diff --git a/src/core/profile_adapter.h b/src/core/profile_adapter.h index efd56e50e..f59768004 100644 --- a/src/core/profile_adapter.h +++ b/src/core/profile_adapter.h @@ -58,7 +58,6 @@ #include <QPointer> #include <QScopedPointer> #include <QString> -#include <QVector> #include "api/qwebengineclientcertificatestore.h" #include "api/qwebenginecookiestore.h" @@ -247,7 +246,7 @@ private: QHash<QByteArray, QSharedPointer<UserNotificationController>> m_persistentNotifications; QList<ProfileAdapterClient*> m_clients; - QVector<WebContentsAdapterClient *> m_webContentsAdapterClients; + QList<WebContentsAdapterClient *> m_webContentsAdapterClients; int m_httpCacheMaxSize; QrcUrlSchemeHandler m_qrcHandler; diff --git a/src/core/profile_adapter_client.h b/src/core/profile_adapter_client.h index 394f92270..07c00044b 100644 --- a/src/core/profile_adapter_client.h +++ b/src/core/profile_adapter_client.h @@ -85,13 +85,6 @@ public: MimeHtmlSaveFormat }; - enum DownloadType { - Attachment = 0, - DownloadAttribute, - UserRequested, - SavePage - }; - // Keep in sync with content::DownloadInterruptReason enum DownloadInterruptReason { NoReason = 0, @@ -136,7 +129,7 @@ public: bool accepted; bool paused; bool done; - int downloadType; + bool isSavePageDownload; int downloadInterruptReason; WebContentsAdapterClient *page; QString suggestedFileName; diff --git a/src/core/profile_qt.h b/src/core/profile_qt.h index 59f5a8c21..11b567b97 100644 --- a/src/core/profile_qt.h +++ b/src/core/profile_qt.h @@ -48,9 +48,6 @@ #include "profile_io_data_qt.h" #include <QtGlobal> -QT_BEGIN_NAMESPACE -class QStringList; -QT_END_NAMESPACE class InMemoryPrefStore; class PrefService; diff --git a/src/core/qtwebengine_sources.gni b/src/core/qtwebengine_sources.gni index cbe51d052..a329da5ab 100644 --- a/src/core/qtwebengine_sources.gni +++ b/src/core/qtwebengine_sources.gni @@ -39,8 +39,19 @@ source_set("qtwebengine_spellcheck_sources") { } } +config("cpp17_config") { + # static initialized constexpr expressions must be compiled always as c++14 or always as c++17 + # and our qtwebengine core sources use them as c++17 + if (is_win) { + cflags_cc = [ "/std:c++17" ] + } else { + cflags_cc = [ "-std=c++17" ] + } +} + source_set("qtwebengine_sources") { configs += [ + ":cpp17_config", "//skia:skia_config", "//third_party/boringssl:external_config", ] diff --git a/src/core/render_view_context_menu_qt.cpp b/src/core/render_view_context_menu_qt.cpp index 8fdae498c..47c8a6e32 100644 --- a/src/core/render_view_context_menu_qt.cpp +++ b/src/core/render_view_context_menu_qt.cpp @@ -39,6 +39,7 @@ #include <QtCore/QCoreApplication> #include "render_view_context_menu_qt.h" +#include "qwebenginecontextmenurequest.h" namespace QtWebEngineCore { @@ -74,8 +75,8 @@ namespace QtWebEngineCore { return QCoreApplication::translate("RenderViewContextMenuQt", qUtf8Printable(names[menuItem])); } - RenderViewContextMenuQt::RenderViewContextMenuQt(const WebEngineContextMenuData &data) - : m_contextData(data) + RenderViewContextMenuQt::RenderViewContextMenuQt(QWebEngineContextMenuRequest *request) + : m_contextData(request) { } @@ -86,15 +87,17 @@ namespace QtWebEngineCore { appendSeparatorItem(); } - if (m_contextData.isEditable() && !m_contextData.spellCheckerSuggestions().isEmpty()) { + if (m_contextData->isContentEditable() + && !m_contextData->spellCheckerSuggestions().isEmpty()) { appendSpellingSuggestionItems(); appendSeparatorItem(); } - if (m_contextData.linkText().isEmpty() && !m_contextData.linkUrl().isValid() && !m_contextData.mediaUrl().isValid()) { - if (m_contextData.isEditable()) + if (m_contextData->linkText().isEmpty() && !m_contextData->filteredLinkUrl().isValid() + && !m_contextData->mediaUrl().isValid()) { + if (m_contextData->isContentEditable()) appendEditableItems(); - else if (!m_contextData.selectedText().isEmpty()) + else if (!m_contextData->selectedText().isEmpty()) appendCopyItem(); else appendPageItems(); @@ -102,27 +105,29 @@ namespace QtWebEngineCore { appendPageItems(); } - if (m_contextData.linkUrl().isValid() || !m_contextData.unfilteredLinkUrl().isEmpty() || !m_contextData.linkUrl().isEmpty()) + if (m_contextData->filteredLinkUrl().isValid() + || !m_contextData->linkUrl().isEmpty() + || !m_contextData->filteredLinkUrl().isEmpty()) appendLinkItems(); - if (m_contextData.mediaUrl().isValid()) { - switch (m_contextData.mediaType()) { - case WebEngineContextMenuData::MediaTypeImage: + if (m_contextData->mediaUrl().isValid()) { + switch (m_contextData->mediaType()) { + case QWebEngineContextMenuRequest::MediaTypeImage: appendSeparatorItem(); appendImageItems(); break; - case WebEngineContextMenuData::MediaTypeCanvas: + case QWebEngineContextMenuRequest::MediaTypeCanvas: Q_UNREACHABLE(); // mediaUrl is invalid for canvases break; - case WebEngineContextMenuData::MediaTypeAudio: - case WebEngineContextMenuData::MediaTypeVideo: + case QWebEngineContextMenuRequest::MediaTypeAudio: + case QWebEngineContextMenuRequest::MediaTypeVideo: appendSeparatorItem(); appendMediaItems(); break; default: break; } - } else if (m_contextData.mediaType() == WebEngineContextMenuData::MediaTypeCanvas) { + } else if (m_contextData->mediaType() == QWebEngineContextMenuRequest::MediaTypeCanvas) { appendSeparatorItem(); appendCanvasItems(); } @@ -160,7 +165,7 @@ namespace QtWebEngineCore { addMenuItem(RenderViewContextMenuQt::Cut); addMenuItem(RenderViewContextMenuQt::Copy); addMenuItem(RenderViewContextMenuQt::Paste); - if (m_contextData.misspelledWord().isEmpty()) { + if (m_contextData->misspelledWord().isEmpty()) { addMenuItem(RenderViewContextMenuQt::PasteAndMatchStyle); addMenuItem(RenderViewContextMenuQt::SelectAll); } @@ -190,7 +195,7 @@ namespace QtWebEngineCore { void RenderViewContextMenuQt::appendMediaItems() { addMenuItem(RenderViewContextMenuQt::ToggleMediaLoop); - if (m_contextData.mediaFlags() & QtWebEngineCore::WebEngineContextMenuData::MediaCanToggleControls) + if (m_contextData->mediaFlags() & QWebEngineContextMenuRequest::MediaCanToggleControls) addMenuItem(RenderViewContextMenuQt::ToggleMediaControls); addMenuItem(RenderViewContextMenuQt::DownloadMediaToDisk); addMenuItem(RenderViewContextMenuQt::CopyMediaUrlToClipboard); @@ -217,10 +222,8 @@ namespace QtWebEngineCore { bool RenderViewContextMenuQt::canViewSource() { - return m_contextData.linkText().isEmpty() - && !m_contextData.linkUrl().isValid() - && !m_contextData.mediaUrl().isValid() - && !m_contextData.isEditable() - && m_contextData.selectedText().isEmpty(); + return m_contextData->linkText().isEmpty() && !m_contextData->filteredLinkUrl().isValid() + && !m_contextData->mediaUrl().isValid() && !m_contextData->isContentEditable() + && m_contextData->selectedText().isEmpty(); } } diff --git a/src/core/render_view_context_menu_qt.h b/src/core/render_view_context_menu_qt.h index e1ee301fc..f818ce200 100644 --- a/src/core/render_view_context_menu_qt.h +++ b/src/core/render_view_context_menu_qt.h @@ -53,6 +53,8 @@ #include "web_contents_adapter_client.h" +QT_FORWARD_DECLARE_CLASS(QWebEngineContextMenuRequest) + namespace QtWebEngineCore { class Q_WEBENGINECORE_PRIVATE_EXPORT RenderViewContextMenuQt @@ -99,7 +101,7 @@ public: static const QString getMenuItemName(RenderViewContextMenuQt::ContextMenuItem menuItem); - RenderViewContextMenuQt(const WebEngineContextMenuData &data); + RenderViewContextMenuQt(QWebEngineContextMenuRequest *data); void initMenu(); protected: @@ -109,7 +111,7 @@ protected: virtual void addMenuItem(ContextMenuItem menuItem) = 0; virtual bool isMenuItemEnabled(ContextMenuItem menuItem) = 0; - const WebEngineContextMenuData &m_contextData; + QWebEngineContextMenuRequest *m_contextData; private: void appendCanvasItems(); diff --git a/src/core/render_widget_host_view_qt.cpp b/src/core/render_widget_host_view_qt.cpp index 525e9924e..fbb4c5bd6 100644 --- a/src/core/render_widget_host_view_qt.cpp +++ b/src/core/render_widget_host_view_qt.cpp @@ -44,9 +44,8 @@ #include "common/qt_messages.h" #include "qtwebenginecoreglobal_p.h" #include "render_widget_host_view_qt_delegate.h" -#include "touch_handle_drawable_client.h" +#include "render_widget_host_view_qt_delegate_client.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" @@ -58,14 +57,13 @@ #include "components/viz/common/surfaces/frame_sink_id_allocator.h" #include "components/viz/host/host_frame_sink_manager.h" #include "content/browser/compositor/image_transport_factory.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/input/synthetic_gesture_target.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" +#include "content/common/content_switches_internal.h" #include "content/common/cursors/webcursor.h" #include "content/common/input_messages.h" #include "third_party/skia/include/core/SkColor.h" @@ -74,9 +72,7 @@ #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/image/image_skia.h" -#include "ui/touch_selection/touch_selection_controller.h" #if defined(USE_OZONE) #include "ui/base/clipboard/scoped_clipboard_writer.h" @@ -88,23 +84,10 @@ #include "ui/base/resource/resource_bundle.h" #endif -#include <private/qguiapplication_p.h> -#include <qpa/qplatforminputcontext.h> -#include <qpa/qplatformintegration.h> -#include <QEvent> -#include <QFocusEvent> #include <QGuiApplication> -#include <QInputMethodEvent> -#include <QTextFormat> -#include <QKeyEvent> -#include <QMouseEvent> #include <QPixmap> #include <QScreen> -#include <QStyleHints> -#include <QVariant> -#include <QWheelEvent> #include <QWindow> -#include <QtGui/private/qinputcontrol_p.h> namespace QtWebEngineCore { @@ -127,50 +110,6 @@ static inline ui::LatencyInfo CreateLatencyInfo(const blink::WebInputEvent& even return latency_info; } -static inline Qt::InputMethodHints toQtInputMethodHints(ui::TextInputType inputType) -{ - switch (inputType) { - case ui::TEXT_INPUT_TYPE_TEXT: - return Qt::ImhPreferLowercase; - case ui::TEXT_INPUT_TYPE_SEARCH: - return Qt::ImhPreferLowercase | Qt::ImhNoAutoUppercase; - case ui::TEXT_INPUT_TYPE_PASSWORD: - return Qt::ImhSensitiveData | Qt::ImhNoPredictiveText | Qt::ImhNoAutoUppercase | Qt::ImhHiddenText; - case ui::TEXT_INPUT_TYPE_EMAIL: - return Qt::ImhEmailCharactersOnly; - case ui::TEXT_INPUT_TYPE_NUMBER: - return Qt::ImhFormattedNumbersOnly; - case ui::TEXT_INPUT_TYPE_TELEPHONE: - return Qt::ImhDialableCharactersOnly; - case ui::TEXT_INPUT_TYPE_URL: - return Qt::ImhUrlCharactersOnly | Qt::ImhNoPredictiveText | Qt::ImhNoAutoUppercase; - case ui::TEXT_INPUT_TYPE_DATE_TIME: - case ui::TEXT_INPUT_TYPE_DATE_TIME_LOCAL: - case ui::TEXT_INPUT_TYPE_DATE_TIME_FIELD: - return Qt::ImhDate | Qt::ImhTime; - case ui::TEXT_INPUT_TYPE_DATE: - case ui::TEXT_INPUT_TYPE_MONTH: - case ui::TEXT_INPUT_TYPE_WEEK: - return Qt::ImhDate; - case ui::TEXT_INPUT_TYPE_TIME: - return Qt::ImhTime; - case ui::TEXT_INPUT_TYPE_TEXT_AREA: - case ui::TEXT_INPUT_TYPE_CONTENT_EDITABLE: - return Qt::ImhMultiLine | Qt::ImhPreferLowercase; - default: - return Qt::ImhNone; - } -} - -static inline int firstAvailableId(const QMap<int, int> &map) -{ - ui::BitSet32 usedIds; - QMap<int, int>::const_iterator end = map.end(); - for (QMap<int, int>::const_iterator it = map.begin(); it != end; ++it) - usedIds.mark_bit(it.value()); - return usedIds.first_unmarked_bit(); -} - static inline ui::GestureProvider::Config QtGestureProviderConfig() { ui::GestureProvider::Config config = ui::GetGestureProviderConfig(ui::GestureProviderConfigType::CURRENT_PLATFORM); // Causes an assert in CreateWebGestureEventFromGestureEventData and we don't need them in Qt. @@ -180,99 +119,6 @@ static inline ui::GestureProvider::Config QtGestureProviderConfig() { return config; } -static inline bool compareTouchPoints(const QTouchEvent::TouchPoint &lhs, const QTouchEvent::TouchPoint &rhs) -{ - // TouchPointPressed < TouchPointMoved < TouchPointReleased - return lhs.state() < rhs.state(); -} - -static inline bool isCommonTextEditShortcut(const QKeyEvent *ke) -{ - return QInputControl::isCommonTextEditShortcut(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, int index = -1) - : touchPoints(touchPoints) - , eventTime(eventTime) - , action(action) - , eventId(++s_eventId) - , flags(flagsFromModifiers(modifiers)) - , index(index) - { - // ACTION_DOWN and ACTION_UP must be accesssed through pointer_index 0 - Q_ASSERT((action != Action::DOWN && action != Action::UP) || index == 0); - } - - uint32_t GetUniqueEventId() const override { return eventId; } - Action GetAction() const override { return action; } - 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(); } - 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 - { - QSizeF diams = touchPoints.at(pointer_index).ellipseDiameters(); - return std::max(diams.height(), diams.width()); - } - float GetTouchMinor(size_t pointer_index) const override - { - QSizeF diams = touchPoints.at(pointer_index).ellipseDiameters(); - return std::min(diams.height(), diams.width()); - } - float GetOrientation(size_t pointer_index) const override - { - return 0; - } - int GetFlags() const override { return flags; } - 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; } - base::TimeTicks GetHistoricalEventTime(size_t historical_index) const override { return base::TimeTicks(); } - 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 (touchPoints.at(pointer_index).flags() & QTouchEvent::TouchPoint::InfoFlag::Pen) ? ui::MotionEvent::ToolType::STYLUS - : ui::MotionEvent::ToolType::FINGER; - } - int GetButtonState() const override { return 0; } - -private: - QList<QTouchEvent::TouchPoint> touchPoints; - base::TimeTicks eventTime; - Action action; - const uint32_t eventId; - int flags; - int index; -}; - -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; -} - // An minimal override to support progressing flings class FlingingCompositor : public ui::Compositor { @@ -304,29 +150,12 @@ RenderWidgetHostViewQt::RenderWidgetHostViewQt(content::RenderWidgetHost *widget : content::RenderWidgetHostViewBase::RenderWidgetHostViewBase(widget) , m_taskRunner(base::ThreadTaskRunnerHandle::Get()) , m_gestureProvider(QtGestureProviderConfig(), this) - , m_sendMotionActionDown(false) - , m_touchMotionStarted(false) - , m_visible(false) - , m_loadVisuallyCommittedState(NotCommitted) - , m_adapterClient(0) - , m_imeInProgress(false) - , m_receivedEmptyImeEvent(false) - , m_isMouseLocked(false) - , m_imState(0) - , m_anchorPositionWithinSelection(-1) - , m_cursorPositionWithinSelection(-1) - , m_cursorPosition(0) - , m_emptyPreviousSelection(true) - , m_wheelAckPending(false) - , m_mouseWheelPhaseHandler(this) , m_frameSinkId(host()->GetFrameSinkId()) + , m_delegateClient(new RenderWidgetHostViewQtDelegateClient(this)) { if (GetTextInputManager()) GetTextInputManager()->AddObserver(this); - const QPlatformInputContext *context = QGuiApplicationPrivate::platformIntegration()->inputContext(); - m_imeHasHiddenTextCapability = context && context->hasCapability(QPlatformInputContext::HiddenTextCapability); - m_rootLayer.reset(new ui::Layer(ui::LAYER_SOLID_COLOR)); m_rootLayer->SetColor(SK_ColorTRANSPARENT); @@ -346,9 +175,6 @@ RenderWidgetHostViewQt::RenderWidgetHostViewQt(content::RenderWidgetHost *widget m_uiCompositor->SetAcceleratedWidget(gfx::kNullAcceleratedWidget); // null means offscreen m_uiCompositor->SetRootLayer(m_rootLayer.get()); - m_displayFrameSink = DisplayFrameSink::findOrCreate(m_uiCompositor->frame_sink_id()); - m_displayFrameSink->connect(this); - if (host()->delegate() && host()->delegate()->GetInputEventRouter()) host()->delegate()->GetInputEventRouter()->AddFrameSinkIdOwner(GetFrameSinkId(), this); @@ -370,8 +196,6 @@ RenderWidgetHostViewQt::~RenderWidgetHostViewQt() QObject::disconnect(m_adapterClientDestroyedConnection); - m_displayFrameSink->disconnect(this); - if (text_input_manager_) text_input_manager_->RemoveObserver(this); @@ -386,7 +210,7 @@ void RenderWidgetHostViewQt::setDelegate(RenderWidgetHostViewQtDelegate* delegat m_deferredShow = false; Show(); } - visualPropertiesChanged(); + delegateClient()->visualPropertiesChanged(); } void RenderWidgetHostViewQt::setAdapterClient(WebContentsAdapterClient *adapterClient) @@ -420,7 +244,7 @@ void RenderWidgetHostViewQt::SetSize(const gfx::Size &sizeInDips) void RenderWidgetHostViewQt::SetBounds(const gfx::Rect &windowRectInDips) { - DCHECK(IsPopup()); + DCHECK(isPopup()); m_delegate->move(toQt(windowRectInDips.origin())); m_delegate->resize(windowRectInDips.width(), windowRectInDips.height()); } @@ -457,7 +281,7 @@ content::BrowserAccessibilityManager* RenderWidgetHostViewQt::CreateBrowserAcces // Set focus to the associated View component. void RenderWidgetHostViewQt::Focus() { - if (!IsPopup()) + if (!isPopup()) m_delegate->setKeyboardFocus(); host()->Focus(); } @@ -507,7 +331,7 @@ bool RenderWidgetHostViewQt::IsShowing() // Retrieve the bounds of the View, in screen coordinates. gfx::Rect RenderWidgetHostViewQt::GetViewBounds() { - return m_viewRectInDips; + return toGfx(delegateClient()->viewRectInDips()); } void RenderWidgetHostViewQt::UpdateBackgroundColor() @@ -535,7 +359,7 @@ blink::mojom::PointerLockResult RenderWidgetHostViewQt::LockMouse(bool request_u if (request_unadjusted_movement) return blink::mojom::PointerLockResult::kUnsupportedOptions; - m_previousMousePosition = QCursor::pos(); + delegateClient()->resetPreviousMousePosition(); m_delegate->lockMouse(); m_isMouseLocked = true; qApp->setOverrideCursor(Qt::BlankCursor); @@ -764,7 +588,7 @@ void RenderWidgetHostViewQt::GetScreenInfo(content::ScreenInfo *results) gfx::Rect RenderWidgetHostViewQt::GetBoundsInRootWindow() { - return m_windowRectInDips; + return toGfx(delegateClient()->windowRectInDips()); } void RenderWidgetHostViewQt::OnUpdateTextInputStateCalled(content::TextInputManager *text_input_manager, RenderWidgetHostViewBase *updated_view, bool did_update_state) @@ -786,16 +610,18 @@ void RenderWidgetHostViewQt::OnUpdateTextInputStateCalled(content::TextInputMana #else m_delegate->setInputMethodHints(toQtInputMethodHints(getTextInputType()) | Qt::ImhNoPredictiveText); #endif - m_surroundingText = toQt(state->value); + QString 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); + surroundingText.remove(state->composition_start, + state->composition_end - state->composition_start); + delegateClient()->setSurroundingText(surroundingText); // In case of text selection, the update is expected in RenderWidgetHostViewQt::selectionChanged(). if (GetSelectedText().empty()) { // At this point it is unknown whether the text input state has been updated due to a text selection. // Keep the cursor position updated for cursor movements too. - m_cursorPosition = state->selection_start; + delegateClient()->setCursorPosition(state->selection_start); m_delegate->inputMethodStateChanged(type != ui::TEXT_INPUT_TYPE_NONE, type == ui::TEXT_INPUT_TYPE_PASSWORD); } @@ -805,14 +631,14 @@ void RenderWidgetHostViewQt::OnUpdateTextInputStateCalled(content::TextInputMana } // Ignore selection change triggered by ime composition unless it clears an actual text selection - if (state->composition_start != -1 && m_emptyPreviousSelection) { + if (state->composition_start != -1 && delegateClient()->isPreviousSelectionEmpty()) { m_imState = 0; return; } m_imState |= ImStateFlags::TextInputStateUpdated; if (m_imState == ImStateFlags::AllFlags) - selectionChanged(); + delegateClient()->selectionChanged(); } void RenderWidgetHostViewQt::OnSelectionBoundsChanged(content::TextInputManager *text_input_manager, RenderWidgetHostViewBase *updated_view) @@ -823,7 +649,7 @@ void RenderWidgetHostViewQt::OnSelectionBoundsChanged(content::TextInputManager m_imState |= ImStateFlags::TextSelectionBoundsUpdated; if (m_imState == ImStateFlags::AllFlags || (m_imState == ImStateFlags::TextSelectionFlags && getTextInputType() == ui::TEXT_INPUT_TYPE_NONE)) { - selectionChanged(); + delegateClient()->selectionChanged(); } } @@ -847,82 +673,10 @@ void RenderWidgetHostViewQt::OnTextSelectionChanged(content::TextInputManager *t m_imState |= ImStateFlags::TextSelectionUpdated; if (m_imState == ImStateFlags::AllFlags || (m_imState == ImStateFlags::TextSelectionFlags && getTextInputType() == ui::TEXT_INPUT_TYPE_NONE)) { - selectionChanged(); + delegateClient()->selectionChanged(); } } -void RenderWidgetHostViewQt::selectionChanged() -{ - // Reset input manager state - m_imState = 0; - ui::TextInputType type = getTextInputType(); - - // Handle text selection out of an input field - if (type == ui::TEXT_INPUT_TYPE_NONE) { - if (GetSelectedText().empty() && m_emptyPreviousSelection) - return; - - // Reset position values to emit selectionChanged signal when clearing text selection - // by clicking into an input field. These values are intended to be used by inputMethodQuery - // so they are not expected to be valid when selection is out of an input field. - m_anchorPositionWithinSelection = -1; - m_cursorPositionWithinSelection = -1; - - m_emptyPreviousSelection = GetSelectedText().empty(); - m_adapterClient->selectionChanged(); - return; - } - - if (GetSelectedText().empty()) { - // RenderWidgetHostViewQt::OnUpdateTextInputStateCalled() does not update the cursor position - // if the selection is cleared because TextInputState changes before the TextSelection change. - Q_ASSERT(text_input_manager_->GetTextInputState()); - m_cursorPosition = text_input_manager_->GetTextInputState()->selection_start; - m_delegate->inputMethodStateChanged(true /*editorVisible*/, type == ui::TEXT_INPUT_TYPE_PASSWORD); - - m_anchorPositionWithinSelection = m_cursorPosition; - m_cursorPositionWithinSelection = m_cursorPosition; - - if (!m_emptyPreviousSelection) { - m_emptyPreviousSelection = true; - m_adapterClient->selectionChanged(); - } - - return; - } - - const content::TextInputManager::TextSelection *selection = text_input_manager_->GetTextSelection(); - if (!selection) - return; - - if (!selection->range().IsValid()) - return; - - int newAnchorPositionWithinSelection = 0; - int newCursorPositionWithinSelection = 0; - - if (text_input_manager_->GetSelectionRegion()->anchor.type() == gfx::SelectionBound::RIGHT) { - newAnchorPositionWithinSelection = selection->range().GetMax() - selection->offset(); - newCursorPositionWithinSelection = selection->range().GetMin() - selection->offset(); - } else { - newAnchorPositionWithinSelection = selection->range().GetMin() - selection->offset(); - newCursorPositionWithinSelection = selection->range().GetMax() - selection->offset(); - } - - if (m_anchorPositionWithinSelection == newAnchorPositionWithinSelection && m_cursorPositionWithinSelection == newCursorPositionWithinSelection) - return; - - m_anchorPositionWithinSelection = newAnchorPositionWithinSelection; - m_cursorPositionWithinSelection = newCursorPositionWithinSelection; - - if (!selection->selected_text().empty()) - m_cursorPosition = newCursorPositionWithinSelection; - - m_emptyPreviousSelection = selection->selected_text().empty(); - m_delegate->inputMethodStateChanged(true /*editorVisible*/, type == ui::TEXT_INPUT_TYPE_PASSWORD); - m_adapterClient->selectionChanged(); -} - void RenderWidgetHostViewQt::OnGestureEvent(const ui::GestureEventData& gesture) { if ((gesture.type() == ui::ET_GESTURE_PINCH_BEGIN @@ -976,36 +730,12 @@ void RenderWidgetHostViewQt::OnDidUpdateVisualPropertiesComplete(const cc::Rende void RenderWidgetHostViewQt::OnDidFirstVisuallyNonEmptyPaint() { - if (m_loadVisuallyCommittedState == NotCommitted) { - m_loadVisuallyCommittedState = DidFirstVisuallyNonEmptyPaint; - } else if (m_loadVisuallyCommittedState == DidFirstCompositorFrameSwap) { - m_adapterClient->loadVisuallyCommitted(); - m_loadVisuallyCommittedState = NotCommitted; - } -} - -void RenderWidgetHostViewQt::scheduleUpdate() -{ - m_taskRunner->PostTask( - FROM_HERE, - base::BindOnce(&RenderWidgetHostViewQt::callUpdate, m_weakPtrFactory.GetWeakPtr())); + m_adapterClient->didFirstVisuallyNonEmptyPaint(); } -void RenderWidgetHostViewQt::callUpdate() +Compositor::Id RenderWidgetHostViewQt::compositorId() { - m_delegate->update(); - - if (m_loadVisuallyCommittedState == NotCommitted) { - m_loadVisuallyCommittedState = DidFirstCompositorFrameSwap; - } else if (m_loadVisuallyCommittedState == DidFirstVisuallyNonEmptyPaint) { - m_adapterClient->loadVisuallyCommitted(); - m_loadVisuallyCommittedState = NotCommitted; - } -} - -QSGNode *RenderWidgetHostViewQt::updatePaintNode(QSGNode *oldNode) -{ - return m_displayFrameSink->updatePaintNode(oldNode, m_delegate.get()); + return m_uiCompositor->frame_sink_id(); } void RenderWidgetHostViewQt::notifyShown() @@ -1021,8 +751,7 @@ void RenderWidgetHostViewQt::notifyShown() m_delegatedFrameHost->AttachToCompositor(m_uiCompositor.get()); m_delegatedFrameHost->WasShown(GetLocalSurfaceIdAllocation().local_surface_id(), - m_viewRectInDips.size(), - base::nullopt); + toGfx(delegateClient()->viewRectInDips().size()), base::nullopt); } void RenderWidgetHostViewQt::notifyHidden() @@ -1035,202 +764,6 @@ void RenderWidgetHostViewQt::notifyHidden() m_delegatedFrameHost->DetachFromCompositor(); } -void RenderWidgetHostViewQt::visualPropertiesChanged() -{ - if (!m_delegate) - return; - - 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) -{ - Q_ASSERT(host()->GetView()); - - switch (event->type()) { - case QEvent::ShortcutOverride: { - QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event); - - auto acceptKeyOutOfInputField = [](QKeyEvent *keyEvent) -> bool { -#ifdef Q_OS_MACOS - // Check if a shortcut is registered for this key sequence. - QKeySequence sequence = QKeySequence ( - (keyEvent->modifiers() | keyEvent->key()) & - ~(Qt::KeypadModifier | Qt::GroupSwitchModifier)); - if (QGuiApplicationPrivate::instance()->shortcutMap.hasShortcutForKeySequence(sequence)) - return false; - - // The following shortcuts are handled out of input field too but - // disabled on macOS to let the blinking menu handling to the - // embedder application (see kKeyboardCodeKeyDownEntries in - // third_party/WebKit/Source/core/editing/EditingBehavior.cpp). - // Let them pass on macOS to generate the corresponding edit command. - return keyEvent->matches(QKeySequence::Copy) - || keyEvent->matches(QKeySequence::Paste) - || keyEvent->matches(QKeySequence::Cut) - || keyEvent->matches(QKeySequence::SelectAll); -#else - return false; -#endif - }; - - if (!inputMethodQuery(Qt::ImEnabled).toBool() && !(inputMethodQuery(Qt::ImHints).toInt() & Qt::ImhHiddenText) && !acceptKeyOutOfInputField(keyEvent)) - return false; - - Q_ASSERT(m_editCommand.empty()); - if (WebEventFactory::getEditCommand(keyEvent, &m_editCommand) - || isCommonTextEditShortcut(keyEvent)) { - event->accept(); - return true; - } - - return false; - } - case QEvent::MouseButtonPress: - Focus(); - Q_FALLTHROUGH(); - case QEvent::MouseButtonRelease: - case QEvent::MouseMove: - // Skip second MouseMove event when a window is being adopted, so that Chromium - // can properly handle further move events. - // Also make sure the adapter client exists to prevent a null pointer dereference, - // because it's possible for a QWebEnginePagePrivate (adapter) instance to be destroyed, - // and then the OS (observed on Windows) might still send mouse move events to a still - // existing popup RWHVQDW instance. - if (m_adapterClient && m_adapterClient->isBeingAdopted()) - return false; - handleMouseEvent(static_cast<QMouseEvent*>(event)); - break; - case QEvent::KeyPress: - case QEvent::KeyRelease: - handleKeyEvent(static_cast<QKeyEvent*>(event)); - break; - case QEvent::Wheel: - handleWheelEvent(static_cast<QWheelEvent*>(event)); - break; - case QEvent::TouchBegin: - Focus(); - Q_FALLTHROUGH(); - case QEvent::TouchUpdate: - case QEvent::TouchEnd: - case QEvent::TouchCancel: - handleTouchEvent(static_cast<QTouchEvent*>(event)); - break; -#if QT_CONFIG(tabletevent) - case QEvent::TabletPress: - Focus(); - Q_FALLTHROUGH(); - case QEvent::TabletRelease: - case QEvent::TabletMove: - handleTabletEvent(static_cast<QTabletEvent*>(event)); - break; -#endif -#ifndef QT_NO_GESTURES - case QEvent::NativeGesture: - handleGestureEvent(static_cast<QNativeGestureEvent *>(event)); - break; -#endif // QT_NO_GESTURES - case QEvent::HoverMove: - handleHoverEvent(static_cast<QHoverEvent*>(event)); - break; - case QEvent::FocusIn: - case QEvent::FocusOut: - handleFocusEvent(static_cast<QFocusEvent*>(event)); - break; - case QEvent::InputMethod: - handleInputMethodEvent(static_cast<QInputMethodEvent*>(event)); - break; - case QEvent::InputMethodQuery: - handleInputMethodQueryEvent(static_cast<QInputMethodQueryEvent*>(event)); - break; - case QEvent::Leave: -#ifdef Q_OS_WIN - if (m_mouseButtonPressed > 0) - return false; -#endif - case QEvent::HoverLeave: - host()->ForwardMouseEvent(WebEventFactory::toWebMouseEvent(event)); - break; - default: - return false; - } - return true; -} - -QVariant RenderWidgetHostViewQt::inputMethodQuery(Qt::InputMethodQuery query) -{ - switch (query) { - case Qt::ImEnabled: { - ui::TextInputType type = getTextInputType(); - bool editorVisible = type != ui::TEXT_INPUT_TYPE_NONE; - // IME manager should disable composition on input fields with ImhHiddenText hint if supported - if (m_imeHasHiddenTextCapability) - return QVariant(editorVisible); - - bool passwordInput = type == ui::TEXT_INPUT_TYPE_PASSWORD; - return QVariant(editorVisible && !passwordInput); - } - case Qt::ImFont: - // TODO: Implement this - return QVariant(); - case Qt::ImCursorRectangle: { - if (text_input_manager_) { - if (auto *region = text_input_manager_->GetSelectionRegion()) { - if (region->focus.GetHeight() > 0) { - gfx::Rect caretRect = gfx::RectBetweenSelectionBounds(region->anchor, region->focus); - if (caretRect.width() == 0) - caretRect.set_width(1); // IME API on Windows expects a width > 0 - return toQt(caretRect); - } - } - } - return QVariant(); - } - case Qt::ImCursorPosition: - return m_cursorPosition; - case Qt::ImAnchorPosition: - return GetSelectedText().empty() ? m_cursorPosition : m_anchorPositionWithinSelection; - case Qt::ImSurroundingText: - return m_surroundingText; - case Qt::ImCurrentSelection: - return toQt(GetSelectedText()); - case Qt::ImMaximumTextLength: - // 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(); - } -} - -void RenderWidgetHostViewQt::closePopup() -{ - // We notify the popup to be closed by telling it that it lost focus. WebKit does the rest - // (hiding the widget and automatic memory cleanup via - // RenderWidget::CloseWidgetSoon() -> RenderWidgetHostImpl::ShutdownAndDestroyWidget(true). - host()->SetActive(false); - host()->LostFocus(); -} - void RenderWidgetHostViewQt::ProcessAckedTouchEvent(const content::TouchEventWithLatencyInfo &touch, content::InputEventAckState ack_result) { Q_UNUSED(touch); const bool eventConsumed = ack_result == content::INPUT_EVENT_ACK_STATE_CONSUMED; @@ -1249,279 +782,46 @@ void RenderWidgetHostViewQt::processMotionEvent(const ui::MotionEvent &motionEve host()->ForwardTouchEventWithLatencyInfo(touchEvent, CreateLatencyInfo(touchEvent)); } -QList<QTouchEvent::TouchPoint> RenderWidgetHostViewQt::mapTouchPointIds(const QList<QTouchEvent::TouchPoint> &inputPoints) -{ - QList<QTouchEvent::TouchPoint> outputPoints = inputPoints; - for (int i = 0; i < outputPoints.size(); ++i) { - QTouchEvent::TouchPoint &point = outputPoints[i]; - - int qtId = point.id(); - QMap<int, int>::const_iterator it = m_touchIdMapping.find(qtId); - if (it == m_touchIdMapping.end()) - it = m_touchIdMapping.insert(qtId, firstAvailableId(m_touchIdMapping)); - point.setId(it.value()); - - if (point.state() == Qt::TouchPointReleased) - m_touchIdMapping.remove(qtId); - } - - return outputPoints; -} - -bool RenderWidgetHostViewQt::IsPopup() const +bool RenderWidgetHostViewQt::isPopup() const { return widget_type_ == content::WidgetType::kPopup; } -void RenderWidgetHostViewQt::handleMouseEvent(QMouseEvent* event) -{ - if (event->type() == QEvent::MouseButtonPress) - m_mouseButtonPressed++; - if (event->type() == QEvent::MouseButtonRelease) - m_mouseButtonPressed--; - - // Don't forward mouse events synthesized by the system, which are caused by genuine touch - // events. Chromium would then process for e.g. a mouse click handler twice, once due to the - // system synthesized mouse event, and another time due to a touch-to-gesture-to-mouse - // transformation done by Chromium. - if (event->source() == Qt::MouseEventSynthesizedBySystem) - return; - handlePointerEvent<QMouseEvent>(event); -} - -void RenderWidgetHostViewQt::handleKeyEvent(QKeyEvent *ev) -{ - if (IsMouseLocked() && ev->key() == Qt::Key_Escape && ev->type() == QEvent::KeyRelease) - UnlockMouse(); - - if (m_receivedEmptyImeEvent) { - // IME composition was not finished with a valid commit string. - // We're getting the composition result in a key event. - if (ev->key() != 0) { - // The key event is not a result of an IME composition. Cancel IME. - host()->ImeCancelComposition(); - m_receivedEmptyImeEvent = false; - } else { - if (ev->type() == QEvent::KeyRelease) { - host()->ImeCommitText(toString16(ev->text()), - std::vector<ui::ImeTextSpan>(), - gfx::Range::InvalidRange(), - 0); - m_receivedEmptyImeEvent = false; - m_imeInProgress = false; - } - return; - } - } - - // Ignore autorepeating KeyRelease events so that the generated web events - // conform to the spec, which requires autorepeat to result in a sequence of - // keypress events and only one final keyup event: - // https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent#Auto-repeat_handling - // https://w3c.github.io/uievents/#dom-keyboardevent-repeat - if (ev->type() == QEvent::KeyRelease && ev->isAutoRepeat()) - return; - - content::NativeWebKeyboardEvent webEvent = WebEventFactory::toWebKeyboardEvent(ev); - if (webEvent.GetType() == blink::WebInputEvent::kRawKeyDown && !m_editCommand.empty()) { - ui::LatencyInfo latency; - latency.set_source_event_type(ui::SourceEventType::KEY_PRESS); - content::EditCommands commands; - commands.emplace_back(m_editCommand, ""); - m_editCommand.clear(); - host()->ForwardKeyboardEventWithCommands(webEvent, latency, &commands, nullptr); - return; - } - - bool keyDownTextInsertion = webEvent.GetType() == blink::WebInputEvent::kRawKeyDown && webEvent.text[0]; - webEvent.skip_in_browser = keyDownTextInsertion; - host()->ForwardKeyboardEvent(webEvent); - - if (keyDownTextInsertion) { - // Blink won't consume the RawKeyDown, but rather the Char event in this case. - // The RawKeyDown is skipped on the way back (see above). - // The same os_event will be set on both NativeWebKeyboardEvents. - webEvent.skip_in_browser = false; - webEvent.SetType(blink::WebInputEvent::kChar); - host()->ForwardKeyboardEvent(webEvent); - } -} - -void RenderWidgetHostViewQt::handleInputMethodEvent(QInputMethodEvent *ev) +bool RenderWidgetHostViewQt::updateScreenInfo() { - // Reset input manager state - m_imState = 0; - - if (!host()) - return; - - QString commitString = ev->commitString(); - QString preeditString = ev->preeditString(); - - int cursorPositionInPreeditString = -1; - gfx::Range selectionRange = gfx::Range::InvalidRange(); - - const QList<QInputMethodEvent::Attribute> &attributes = ev->attributes(); - std::vector<ui::ImeTextSpan> underlines; - bool hasSelection = false; - - for (const auto &attribute : attributes) { - switch (attribute.type) { - case QInputMethodEvent::TextFormat: { - if (preeditString.isEmpty()) - break; - - int start = qMin(attribute.start, (attribute.start + attribute.length)); - int end = qMax(attribute.start, (attribute.start + attribute.length)); - - // Blink does not support negative position values. Adjust start and end positions - // to non-negative values. - if (start < 0) { - start = 0; - end = qMax(0, start + end); - } - - underlines.push_back(ui::ImeTextSpan(ui::ImeTextSpan::Type::kComposition, start, end, - ui::ImeTextSpan::Thickness::kThin, ui::ImeTextSpan::UnderlineStyle::kSolid, - SK_ColorTRANSPARENT)); - - QTextCharFormat format = qvariant_cast<QTextFormat>(attribute.value).toCharFormat(); - if (format.underlineStyle() != QTextCharFormat::NoUnderline) - underlines.back().underline_color = toSk(format.underlineColor()); - - break; - } - case QInputMethodEvent::Cursor: - // Always set the position of the cursor, even if it's marked invisible by Qt, otherwise - // there is no way the user will know which part of the composition string will be - // changed, when performing an IME-specific action (like selecting a different word - // suggestion). - cursorPositionInPreeditString = attribute.start; - break; - case QInputMethodEvent::Selection: - hasSelection = true; - - // Cancel IME composition - if (preeditString.isEmpty() && attribute.start + attribute.length == 0) { - selectionRange.set_start(0); - selectionRange.set_end(0); - break; - } - - selectionRange.set_start(qMin(attribute.start, (attribute.start + attribute.length))); - selectionRange.set_end(qMax(attribute.start, (attribute.start + attribute.length))); - break; - default: - break; - } - } - - if (!selectionRange.IsValid()) { - // We did not receive a valid selection range, hence the range is going to mark the - // cursor position. - int newCursorPosition = - (cursorPositionInPreeditString < 0) ? preeditString.length() - : cursorPositionInPreeditString; - selectionRange.set_start(newCursorPosition); - selectionRange.set_end(newCursorPosition); - } - - if (hasSelection) { - content::mojom::FrameInputHandler *frameInputHandler = getFrameInputHandler(); - if (frameInputHandler) - frameInputHandler->SetEditableSelectionOffsets(selectionRange.start(), selectionRange.end()); - } - - int replacementLength = ev->replacementLength(); - gfx::Range replacementRange = gfx::Range::InvalidRange(); - - if (replacementLength > 0) - { - int replacementStart = ev->replacementStart() < 0 ? m_cursorPosition + ev->replacementStart() : ev->replacementStart(); - if (replacementStart >= 0 && replacementStart < m_surroundingText.length()) - replacementRange = gfx::Range(replacementStart, replacementStart + replacementLength); - } - - // There are so-far two known cases, when an empty QInputMethodEvent is received. - // First one happens when backspace is used to remove the last character in the pre-edit - // string, thus signaling the end of the composition. - // The second one happens (on Windows) when a Korean char gets composed, but instead of - // the event having a commit string, both strings are empty, and the actual char is received - // as a QKeyEvent after the QInputMethodEvent is processed. - // In lieu of the second case, we can't simply cancel the composition on an empty event, - // and then add the Korean char when QKeyEvent is received, because that leads to text - // flickering in the textarea (or any other element). - // Instead we postpone the processing of the empty QInputMethodEvent by posting it - // to the same focused object, and cancelling the composition on the next event loop tick. - if (commitString.isEmpty() && preeditString.isEmpty() && replacementLength == 0) { - if (!m_receivedEmptyImeEvent && m_imeInProgress && !hasSelection) { - m_receivedEmptyImeEvent = true; - QInputMethodEvent *eventCopy = new QInputMethodEvent(*ev); - QGuiApplication::postEvent(qApp->focusObject(), eventCopy); - } else { - m_receivedEmptyImeEvent = false; - if (m_imeInProgress) { - m_imeInProgress = false; - host()->ImeCancelComposition(); - } - } - - return; - } - - m_receivedEmptyImeEvent = false; + content::ScreenInfo oldScreenInfo = m_screenInfo; + QScreen *screen = m_delegate->window() ? m_delegate->window()->screen() : nullptr; - // Finish compostion: insert or erase text. - if (!commitString.isEmpty() || replacementLength > 0) { - host()->ImeCommitText(toString16(commitString), - underlines, - replacementRange, - 0); - m_imeInProgress = false; + if (screen) { + m_screenInfo.device_scale_factor = screen->devicePixelRatio(); + m_screenInfo.depth_per_component = 8; + m_screenInfo.depth = screen->depth(); + m_screenInfo.is_monochrome = (m_screenInfo.depth == 1); + m_screenInfo.rect = toGfx(screen->geometry()); + m_screenInfo.available_rect = toGfx(screen->availableGeometry()); + } else { + m_screenInfo.device_scale_factor = qGuiApp->devicePixelRatio(); } - // Update or start new composition. - // Be aware of that, we might get a commit string and a pre-edit string in a single event and - // this means a new composition. - if (!preeditString.isEmpty()) { - host()->ImeSetComposition(toString16(preeditString), - underlines, - replacementRange, - selectionRange.start(), - selectionRange.end()); - m_imeInProgress = true; - } + return (m_screenInfo != oldScreenInfo); } -void RenderWidgetHostViewQt::handleInputMethodQueryEvent(QInputMethodQueryEvent *ev) -{ - Qt::InputMethodQueries queries = ev->queries(); - for (uint i = 0; i < 32; ++i) { - Qt::InputMethodQuery query = (Qt::InputMethodQuery)(int)(queries & (1<<i)); - if (query) { - QVariant v = inputMethodQuery(query); - ev->setValue(query, v); - } - } - ev->accept(); -} - -void RenderWidgetHostViewQt::handleWheelEvent(QWheelEvent *ev) +void RenderWidgetHostViewQt::handleWheelEvent(QWheelEvent *event) { if (!m_wheelAckPending) { Q_ASSERT(m_pendingWheelEvents.isEmpty()); - blink::WebMouseWheelEvent webEvent = WebEventFactory::toWebWheelEvent(ev); + blink::WebMouseWheelEvent webEvent = WebEventFactory::toWebWheelEvent(event); m_wheelAckPending = (webEvent.phase != blink::WebMouseWheelEvent::kPhaseEnded); - m_mouseWheelPhaseHandler.AddPhaseIfNeededAndScheduleEndEvent(webEvent, false); + GetMouseWheelPhaseHandler()->AddPhaseIfNeededAndScheduleEndEvent(webEvent, false); host()->ForwardWheelEvent(webEvent); return; } if (!m_pendingWheelEvents.isEmpty()) { // Try to combine with this wheel event with the last pending one. - if (WebEventFactory::coalesceWebWheelEvent(m_pendingWheelEvents.last(), ev)) + if (WebEventFactory::coalesceWebWheelEvent(m_pendingWheelEvents.last(), event)) return; } - m_pendingWheelEvents.append(WebEventFactory::toWebWheelEvent(ev)); + m_pendingWheelEvents.append(WebEventFactory::toWebWheelEvent(event)); } void RenderWidgetHostViewQt::WheelEventAck(const blink::WebMouseWheelEvent &event, content::InputEventAckState /*ack_result*/) @@ -1558,250 +858,6 @@ content::MouseWheelPhaseHandler *RenderWidgetHostViewQt::GetMouseWheelPhaseHandl return &m_mouseWheelPhaseHandler; } -void RenderWidgetHostViewQt::clearPreviousTouchMotionState() -{ - m_previousTouchPoints.clear(); - m_touchMotionStarted = false; -} - -#ifndef QT_NO_GESTURES -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)); - } -} -#endif - -void RenderWidgetHostViewQt::handleTouchEvent(QTouchEvent *ev) -{ - // On macOS instead of handling touch events, we use the OS provided QNativeGestureEvents. -#ifdef Q_OS_MACOS - if (ev->spontaneous()) { - return; - } else { - VLOG(1) - << "Sending simulated touch events to Chromium does not work properly on macOS. " - "Consider using QNativeGestureEvents or QMouseEvents."; - } -#endif - - // Chromium expects the touch event timestamps to be comparable to base::TimeTicks::Now(). - // Most importantly we also have to preserve the relative time distance between events. - // Calculate a delta between event timestamps and Now() on the first received event, and - // apply this delta to all successive events. This delta is most likely smaller than it - // should by calculating it here but this will hopefully cause less than one frame of delay. - base::TimeTicks eventTimestamp = base::TimeTicks() + base::TimeDelta::FromMilliseconds(ev->timestamp()); - if (m_eventsToNowDelta == base::TimeDelta()) - m_eventsToNowDelta = base::TimeTicks::Now() - eventTimestamp; - eventTimestamp += m_eventsToNowDelta; - - QList<QTouchEvent::TouchPoint> touchPoints = mapTouchPointIds(ev->touchPoints()); - // Make sure that ACTION_POINTER_DOWN is delivered before ACTION_MOVE, - // and ACTION_MOVE before ACTION_POINTER_UP. - std::sort(touchPoints.begin(), touchPoints.end(), compareTouchPoints); - - // Check first if the touch event should be routed to the selectionController - if (!touchPoints.isEmpty()) { - 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)) { - m_previousTouchPoints = touchPoints; - ev->accept(); - return; - } - } else { - // An empty touchPoints always corresponds to a TouchCancel event. - // We can't forward touch cancellations without a previously processed touch event, - // as Chromium expects the previous touchPoints for Action::CANCEL. - // If both are empty that means the TouchCancel was sent without an ongoing touch, - // so there's nothing to cancel anyway. - touchPoints = m_previousTouchPoints; - if (touchPoints.isEmpty()) - return; - - MotionEventQt cancelEvent(touchPoints, eventTimestamp, ui::MotionEvent::Action::CANCEL, ev->modifiers()); - if (m_touchSelectionController->WillHandleTouchEvent(cancelEvent)) { - m_previousTouchPoints.clear(); - 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; - break; - case QEvent::TouchCancel: - { - // Only process TouchCancel events received following a TouchBegin or TouchUpdate event - if (m_touchMotionStarted) { - MotionEventQt cancelEvent(touchPoints, eventTimestamp, ui::MotionEvent::Action::CANCEL, ev->modifiers()); - processMotionEvent(cancelEvent); - } - - clearPreviousTouchMotionState(); - return; - } - case QEvent::TouchEnd: - clearPreviousTouchMotionState(); - m_touchSelectionControllerClient->onTouchUp(); - break; - default: - break; - } - - if (m_imeInProgress && ev->type() == QEvent::TouchBegin) { - m_imeInProgress = false; - // Tell input method to commit the pre-edit string entered so far, and finish the - // composition operation. -#ifdef Q_OS_WIN - // Yes the function name is counter-intuitive, but commit isn't actually implemented - // by the Windows QPA, and reset does exactly what is necessary in this case. - qApp->inputMethod()->reset(); -#else - qApp->inputMethod()->commit(); -#endif - } - - for (int i = 0; i < touchPoints.size(); ++i) { - ui::MotionEvent::Action action; - switch (touchPoints[i].state()) { - case Qt::TouchPointPressed: - if (m_sendMotionActionDown) { - action = ui::MotionEvent::Action::DOWN; - m_sendMotionActionDown = false; - } else { - action = ui::MotionEvent::Action::POINTER_DOWN; - } - break; - case Qt::TouchPointMoved: - action = ui::MotionEvent::Action::MOVE; - break; - case Qt::TouchPointReleased: - action = touchPoints.size() > 1 ? ui::MotionEvent::Action::POINTER_UP : - ui::MotionEvent::Action::UP; - break; - default: - // Ignore Qt::TouchPointStationary - continue; - } - - MotionEventQt motionEvent(touchPoints, eventTimestamp, action, ev->modifiers(), i); - processMotionEvent(motionEvent); - } - - m_previousTouchPoints = touchPoints; -} - -#if QT_CONFIG(tabletevent) -void RenderWidgetHostViewQt::handleTabletEvent(QTabletEvent *event) -{ - handlePointerEvent<QTabletEvent>(event); -} -#endif - -template<class T> -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); - if ((webEvent.GetType() == blink::WebInputEvent::kMouseDown || webEvent.GetType() == blink::WebInputEvent::kMouseUp) - && webEvent.button == blink::WebMouseEvent::Button::kNoButton) { - // Blink can only handle the 5 main mouse-buttons and may assert when processing mouse-down for no button. - LOG(INFO) << "Unhandled mouse button"; - return; - } - - if (webEvent.GetType() == blink::WebInputEvent::kMouseDown) { - if (event->button() != m_clickHelper.lastPressButton - || (event->timestamp() - m_clickHelper.lastPressTimestamp > static_cast<ulong>(qGuiApp->styleHints()->mouseDoubleClickInterval())) - || (event->pos() - m_clickHelper.lastPressPosition).manhattanLength() > qGuiApp->styleHints()->startDragDistance() - || m_clickHelper.clickCounter >= 3) - m_clickHelper.clickCounter = 0; - - m_clickHelper.lastPressTimestamp = event->timestamp(); - webEvent.click_count = ++m_clickHelper.clickCounter; - m_clickHelper.lastPressButton = event->button(); - m_clickHelper.lastPressPosition = QPointF(event->pos()).toPoint(); - } - - if (webEvent.GetType() == blink::WebInputEvent::kMouseUp) - webEvent.click_count = m_clickHelper.clickCounter; - - webEvent.movement_x = event->globalX() - m_previousMousePosition.x(); - webEvent.movement_y = event->globalY() - m_previousMousePosition.y(); - - if (IsMouseLocked()) - QCursor::setPos(m_previousMousePosition); - else - m_previousMousePosition = event->globalPos(); - - if (m_imeInProgress && webEvent.GetType() == blink::WebInputEvent::kMouseDown) { - m_imeInProgress = false; - // Tell input method to commit the pre-edit string entered so far, and finish the - // composition operation. -#ifdef Q_OS_WIN - // Yes the function name is counter-intuitive, but commit isn't actually implemented - // by the Windows QPA, and reset does exactly what is necessary in this case. - qApp->inputMethod()->reset(); -#else - qApp->inputMethod()->commit(); -#endif - } - - host()->ForwardMouseEvent(webEvent); -} - -void RenderWidgetHostViewQt::handleHoverEvent(QHoverEvent *ev) -{ - host()->ForwardMouseEvent(WebEventFactory::toWebMouseEvent(ev)); -} - -void RenderWidgetHostViewQt::handleFocusEvent(QFocusEvent *ev) -{ - if (ev->gotFocus()) { - host()->GotFocus(); - host()->SetActive(true); - content::RenderViewHostImpl *viewHost = content::RenderViewHostImpl::From(host()); - Q_ASSERT(viewHost); - if (ev->reason() == Qt::TabFocusReason) - viewHost->SetInitialFocus(false); - else if (ev->reason() == Qt::BacktabFocusReason) - viewHost->SetInitialFocus(true); - ev->accept(); - - m_adapterClient->webContentsAdapter()->handlePendingMouseLockPermission(); - } else if (ev->lostFocus()) { - host()->SetActive(false); - host()->LostFocus(); - ev->accept(); - } -} - content::RenderFrameHost *RenderWidgetHostViewQt::getFocusedFrameHost() { content::RenderViewHostImpl *viewHost = content::RenderViewHostImpl::From(host()); diff --git a/src/core/render_widget_host_view_qt.h b/src/core/render_widget_host_view_qt.h index 18ea8b9c2..2bc90a558 100644 --- a/src/core/render_widget_host_view_qt.h +++ b/src/core/render_widget_host_view_qt.h @@ -40,7 +40,7 @@ #ifndef RENDER_WIDGET_HOST_VIEW_QT_H #define RENDER_WIDGET_HOST_VIEW_QT_H -#include "compositor/display_frame_sink.h" +#include "compositor/compositor.h" #include "delegated_frame_host_client_qt.h" #include "render_widget_host_view_qt_delegate.h" @@ -52,18 +52,9 @@ #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/public/browser/render_process_host_observer.h" -#include "gpu/ipc/common/gpu_messages.h" #include "ui/events/gesture_detection/filtered_gesture_provider.h" -#include <QMap> -#include <QPoint> -#include <QtGlobal> -#include <QtGui/QTouchEvent> - -QT_BEGIN_NAMESPACE -class QAccessibleInterface; -QT_END_NAMESPACE +QT_FORWARD_DECLARE_CLASS(QAccessibleInterface) namespace content { class RenderFrameHost; @@ -79,41 +70,17 @@ class TouchSelectionController; namespace QtWebEngineCore { -class TouchHandleDrawableClient; +class RenderWidgetHostViewQtDelegateClient; class TouchSelectionControllerClientQt; -class TouchSelectionMenuController; - -struct MultipleMouseClickHelper -{ - QPoint lastPressPosition; - Qt::MouseButton lastPressButton; - int clickCounter; - ulong lastPressTimestamp; - - MultipleMouseClickHelper() - : lastPressPosition(QPoint()) - , lastPressButton(Qt::NoButton) - , clickCounter(0) - , lastPressTimestamp(0) - { - } -}; +class WebContentsAdapterClient; class RenderWidgetHostViewQt : public content::RenderWidgetHostViewBase , public ui::GestureProviderClient - , public RenderWidgetHostViewQtDelegateClient , public base::SupportsWeakPtr<RenderWidgetHostViewQt> , public content::TextInputManager::Observer - , public DisplayConsumer { public: - enum LoadVisuallyCommittedState { - NotCommitted, - DidFirstVisuallyNonEmptyPaint, - DidFirstCompositorFrameSwap - }; - RenderWidgetHostViewQt(content::RenderWidgetHost* widget); ~RenderWidgetHostViewQt(); @@ -121,6 +88,7 @@ public: void setDelegate(RenderWidgetHostViewQtDelegate *delegate); WebContentsAdapterClient *adapterClient() { return m_adapterClient; } void setAdapterClient(WebContentsAdapterClient *adapterClient); + RenderWidgetHostViewQtDelegateClient *delegateClient() const { return m_delegateClient.get(); } void InitAsChild(gfx::NativeView) override; void InitAsPopup(content::RenderWidgetHostView*, const gfx::Rect&) override; @@ -172,146 +140,95 @@ public: void DidStopFlinging() override; std::unique_ptr<content::SyntheticGestureTarget> CreateSyntheticGestureTarget() override; ui::Compositor *GetCompositor() override; +#if defined(OS_MACOSX) + void SetActive(bool active) override { QT_NOT_YET_IMPLEMENTED } + void SpeakSelection() override { QT_NOT_YET_IMPLEMENTED } + void ShowDefinitionForSelection() override { QT_NOT_YET_IMPLEMENTED } +#endif // defined(OS_MACOSX) // Overridden from ui::GestureProviderClient. void OnGestureEvent(const ui::GestureEventData& gesture) override; - // Overridden from RenderWidgetHostViewQtDelegateClient. - QSGNode *updatePaintNode(QSGNode *) override; - void notifyShown() override; - void notifyHidden() override; - void visualPropertiesChanged() override; - bool forwardEvent(QEvent *) override; - QVariant inputMethodQuery(Qt::InputMethodQuery query) override; - void closePopup() override; - // Overridden from content::TextInputManager::Observer void OnUpdateTextInputStateCalled(content::TextInputManager *text_input_manager, RenderWidgetHostViewBase *updated_view, bool did_update_state) override; void OnSelectionBoundsChanged(content::TextInputManager *text_input_manager, RenderWidgetHostViewBase *updated_view) override; void OnTextSelectionChanged(content::TextInputManager *text_input_manager, RenderWidgetHostViewBase *updated_view) override; - void handleMouseEvent(QMouseEvent*); - void handleKeyEvent(QKeyEvent*); - void handleWheelEvent(QWheelEvent*); - void handleTouchEvent(QTouchEvent*); -#if QT_CONFIG(tabletevent) - void handleTabletEvent(QTabletEvent *ev); -#endif -#ifndef QT_NO_GESTURES - void handleGestureEvent(QNativeGestureEvent *); -#endif - void handleHoverEvent(QHoverEvent*); - void handleFocusEvent(QFocusEvent*); - void handleInputMethodEvent(QInputMethodEvent*); - void handleInputMethodQueryEvent(QInputMethodQueryEvent*); - - template<class T> void handlePointerEvent(T*); - -#if defined(OS_MACOSX) - void SetActive(bool active) override { QT_NOT_YET_IMPLEMENTED } - void SpeakSelection() override { QT_NOT_YET_IMPLEMENTED } - void ShowDefinitionForSelection() override { QT_NOT_YET_IMPLEMENTED } -#endif // defined(OS_MACOSX) - // Overridden from content::BrowserAccessibilityDelegate content::BrowserAccessibilityManager* CreateBrowserAccessibilityManager(content::BrowserAccessibilityDelegate* delegate, bool for_root_frame) override; - // Called from WebContentsDelegateQt - void OnDidFirstVisuallyNonEmptyPaint(); - // Overridden from content::RenderFrameMetadataProvider::Observer void OnRenderFrameMetadataChangedAfterActivation() override; - // Overridden from DisplayConsumer - void scheduleUpdate() override; + // Called from RenderWidgetHostViewQtDelegateClient. + Compositor::Id compositorId(); + void notifyShown(); + void notifyHidden(); + bool updateScreenInfo(); + void handleWheelEvent(QWheelEvent *); + void processMotionEvent(const ui::MotionEvent &motionEvent); + void resetInputManagerState() { m_imState = 0; } + // Called from WebContentsDelegateQt. + void OnDidFirstVisuallyNonEmptyPaint(); + + // Called from WebContentsAdapter. gfx::SizeF lastContentsSize() const { return m_lastContentsSize; } gfx::Vector2dF lastScrollOffset() const { return m_lastScrollOffset; } + ui::TextInputType getTextInputType() const; + content::mojom::FrameInputHandler *getFrameInputHandler(); + ui::TouchSelectionController *getTouchSelectionController() const { return m_touchSelectionController.get(); } TouchSelectionControllerClientQt *getTouchSelectionControllerClient() const { return m_touchSelectionControllerClient.get(); } - content::mojom::FrameInputHandler *getFrameInputHandler(); - ui::TextInputType getTextInputType() const; + + void synchronizeVisualProperties( + const base::Optional<viz::LocalSurfaceIdAllocation> &childSurfaceId); private: friend class DelegatedFrameHostClientQt; - void processMotionEvent(const ui::MotionEvent &motionEvent); - void clearPreviousTouchMotionState(); - QList<QTouchEvent::TouchPoint> mapTouchPointIds(const QList<QTouchEvent::TouchPoint> &inputPoints); - - bool IsPopup() const; - - void selectionChanged(); + bool isPopup() const; content::RenderFrameHost *getFocusedFrameHost(); - void synchronizeVisualProperties(const base::Optional<viz::LocalSurfaceIdAllocation> &childSurfaceId); - - void callUpdate(); - - // 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; - scoped_refptr<base::SingleThreadTaskRunner> m_taskRunner; - ui::FilteredGestureProvider m_gestureProvider; - base::TimeDelta m_eventsToNowDelta; - bool m_sendMotionActionDown; - bool m_touchMotionStarted; - QMap<int, int> m_touchIdMapping; - QList<QTouchEvent::TouchPoint> m_previousTouchPoints; + viz::FrameSinkId m_frameSinkId; + std::unique_ptr<RenderWidgetHostViewQtDelegateClient> m_delegateClient; std::unique_ptr<RenderWidgetHostViewQtDelegate> m_delegate; + QMetaObject::Connection m_adapterClientDestroyedConnection; + WebContentsAdapterClient *m_adapterClient = nullptr; - bool m_visible; + bool m_isMouseLocked = false; + bool m_visible = false; bool m_deferredShow = false; - DelegatedFrameHostClientQt m_delegatedFrameHostClient{this}; + gfx::Vector2dF m_lastScrollOffset; + gfx::SizeF m_lastContentsSize; + DelegatedFrameHostClientQt m_delegatedFrameHostClient { this }; + + // VIZ + content::ScreenInfo m_screenInfo; std::unique_ptr<content::DelegatedFrameHost> m_delegatedFrameHost; std::unique_ptr<ui::Layer> m_rootLayer; std::unique_ptr<ui::Compositor> m_uiCompositor; - scoped_refptr<DisplayFrameSink> m_displayFrameSink; - LoadVisuallyCommittedState m_loadVisuallyCommittedState; - - QMetaObject::Connection m_adapterClientDestroyedConnection; - WebContentsAdapterClient *m_adapterClient; - MultipleMouseClickHelper m_clickHelper; - - bool m_imeInProgress; - bool m_receivedEmptyImeEvent; - QPoint m_previousMousePosition; - bool m_isMouseLocked; - - gfx::Vector2dF m_lastScrollOffset; - gfx::SizeF m_lastContentsSize; viz::ParentLocalSurfaceIdAllocator m_dfhLocalSurfaceIdAllocator; viz::ParentLocalSurfaceIdAllocator m_uiCompositorLocalSurfaceIdAllocator; - uint m_imState; - int m_anchorPositionWithinSelection; - int m_cursorPositionWithinSelection; - uint m_cursorPosition; - bool m_emptyPreviousSelection; - QString m_surroundingText; - - bool m_imeHasHiddenTextCapability; + // IME + uint m_imState = 0; - bool m_wheelAckPending; + // Wheel + bool m_wheelAckPending = false; QList<blink::WebMouseWheelEvent> m_pendingWheelEvents; - content::MouseWheelPhaseHandler m_mouseWheelPhaseHandler; - viz::FrameSinkId m_frameSinkId; - - std::string m_editCommand; + content::MouseWheelPhaseHandler m_mouseWheelPhaseHandler { this }; + // TouchSelection std::unique_ptr<TouchSelectionControllerClientQt> m_touchSelectionControllerClient; std::unique_ptr<ui::TouchSelectionController> m_touchSelectionController; gfx::SelectionBound m_selectionStart; gfx::SelectionBound m_selectionEnd; - base::WeakPtrFactory<RenderWidgetHostViewQt> m_weakPtrFactory{this}; - - uint m_mouseButtonPressed = 0; + base::WeakPtrFactory<RenderWidgetHostViewQt> m_weakPtrFactory { this }; }; } // 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 46f1802a6..dfbd3b26a 100644 --- a/src/core/render_widget_host_view_qt_delegate.h +++ b/src/core/render_widget_host_view_qt_delegate.h @@ -53,39 +53,18 @@ #include "qtwebenginecoreglobal_p.h" -#include <QRect> -#include <QtGui/qwindowdefs.h> +#include <QtCore/QRect> +#include <QtGui/QColor> +#include <QtGui/QCursor> +#include <QtGui/QImage> QT_BEGIN_NAMESPACE -class QEvent; -class QInputMethodEvent; -class QSGLayer; -class QSGNode; -class QSGRectangleNode; -class QSGTexture; -class QVariant; class QWheelEvent; - -class QSGImageNode; - +class QWindow; QT_END_NAMESPACE namespace QtWebEngineCore { -class WebContentsAdapterClient; - -class Q_WEBENGINECORE_PRIVATE_EXPORT RenderWidgetHostViewQtDelegateClient { -public: - virtual ~RenderWidgetHostViewQtDelegateClient() { } - virtual QSGNode *updatePaintNode(QSGNode *) = 0; - virtual void notifyShown() = 0; - virtual void notifyHidden() = 0; - virtual void visualPropertiesChanged() = 0; - virtual bool forwardEvent(QEvent *) = 0; - virtual QVariant inputMethodQuery(Qt::InputMethodQuery query) = 0; - virtual void closePopup() = 0; -}; - class Q_WEBENGINECORE_PRIVATE_EXPORT RenderWidgetHostViewQtDelegate { public: virtual ~RenderWidgetHostViewQtDelegate() { } @@ -100,18 +79,12 @@ public: virtual void hide() = 0; virtual bool isVisible() const = 0; virtual QWindow* window() const = 0; - virtual QSGTexture *createTextureFromImage(const QImage &) = 0; - virtual QSGLayer *createLayer() = 0; - virtual QSGImageNode *createImageNode() = 0; - virtual QSGRectangleNode *createRectangleNode() = 0; - virtual void update() = 0; virtual void updateCursor(const QCursor &) = 0; virtual void resize(int width, int height) = 0; virtual void move(const QPoint &) = 0; virtual void inputMethodStateChanged(bool editorVisible, bool passwordInput) = 0; virtual void setInputMethodHints(Qt::InputMethodHints hints) = 0; virtual void setClearColor(const QColor &color) = 0; - virtual bool copySurface(const QRect &, const QSize &, QImage &) = 0; virtual void unhandledWheelEvent(QWheelEvent *) {} }; diff --git a/src/core/render_widget_host_view_qt_delegate_client.cpp b/src/core/render_widget_host_view_qt_delegate_client.cpp new file mode 100644 index 000000000..5e15c2353 --- /dev/null +++ b/src/core/render_widget_host_view_qt_delegate_client.cpp @@ -0,0 +1,977 @@ +/**************************************************************************** +** +** Copyright (C) 2020 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_delegate_client.h" + +#include "render_widget_host_view_qt.h" +#include "touch_selection_controller_client_qt.h" +#include "type_conversion.h" +#include "web_contents_adapter.h" +#include "web_contents_adapter_client.h" +#include "web_event_factory.h" + +#include "content/browser/renderer_host/render_view_host_impl.h" +#include "ui/touch_selection/touch_selection_controller.h" + +#include <QEvent> +#include <QInputMethodEvent> +#include <QSGNode> +#include <QStyleHints> +#include <QTextFormat> +#include <QVariant> + +#include <private/qguiapplication_p.h> +#include <qpa/qplatforminputcontext.h> +#include <qpa/qplatformintegration.h> +#include <QtGui/private/qinputcontrol_p.h> + +namespace QtWebEngineCore { + +static inline int firstAvailableId(const QMap<int, int> &map) +{ + ui::BitSet32 usedIds; + QMap<int, int>::const_iterator end = map.end(); + for (QMap<int, int>::const_iterator it = map.begin(); it != end; ++it) + usedIds.mark_bit(it.value()); + return usedIds.first_unmarked_bit(); +} + +static QList<QTouchEvent::TouchPoint> +mapTouchPointIds(const QList<QTouchEvent::TouchPoint> &inputPoints) +{ + static QMap<int, int> touchIdMapping; + QList<QTouchEvent::TouchPoint> outputPoints = inputPoints; + for (int i = 0; i < outputPoints.size(); ++i) { + QTouchEvent::TouchPoint &point = outputPoints[i]; + + int qtId = point.id(); + QMap<int, int>::const_iterator it = touchIdMapping.find(qtId); + if (it == touchIdMapping.end()) + it = touchIdMapping.insert(qtId, firstAvailableId(touchIdMapping)); + QMutableEventPoint &mut = QMutableEventPoint::from(point); + mut.setId(it.value()); + + if (point.state() == QEventPoint::State::Released) + touchIdMapping.remove(qtId); + } + + return outputPoints; +} + +static inline bool compareTouchPoints(const QTouchEvent::TouchPoint &lhs, + const QTouchEvent::TouchPoint &rhs) +{ + // TouchPointPressed < TouchPointMoved < TouchPointReleased + return lhs.state() < rhs.state(); +} + +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, int index = -1) + : touchPoints(touchPoints) + , eventTime(eventTime) + , action(action) + , eventId(++s_eventId) + , flags(flagsFromModifiers(modifiers)) + , index(index) + { + // ACTION_DOWN and ACTION_UP must be accesssed through pointer_index 0 + Q_ASSERT((action != Action::DOWN && action != Action::UP) || index == 0); + } + + uint32_t GetUniqueEventId() const override { return eventId; } + Action GetAction() const override { return action; } + 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).position().x(); + } + float GetY(size_t pointer_index) const override + { + return touchPoints.at(pointer_index).position().y(); + } + float GetRawX(size_t pointer_index) const override + { + return touchPoints.at(pointer_index).globalPosition().x(); + } + float GetRawY(size_t pointer_index) const override + { + return touchPoints.at(pointer_index).globalPosition().y(); + } + float GetTouchMajor(size_t pointer_index) const override + { + QSizeF diams = touchPoints.at(pointer_index).ellipseDiameters(); + return std::max(diams.height(), diams.width()); + } + float GetTouchMinor(size_t pointer_index) const override + { + QSizeF diams = touchPoints.at(pointer_index).ellipseDiameters(); + return std::min(diams.height(), diams.width()); + } + float GetOrientation(size_t pointer_index) const override { return 0; } + int GetFlags() const override { return flags; } + 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; } + base::TimeTicks GetHistoricalEventTime(size_t historical_index) const override + { + return base::TimeTicks(); + } + 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; + } + + int GetButtonState() const override { return 0; } + +private: + QList<QTouchEvent::TouchPoint> touchPoints; + base::TimeTicks eventTime; + Action action; + const uint32_t eventId; + int flags; + int index; +}; + +RenderWidgetHostViewQtDelegateClient::RenderWidgetHostViewQtDelegateClient( + RenderWidgetHostViewQt *rwhv) + : m_rwhv(rwhv) +{ + Q_ASSERT(rwhv); + + const QPlatformInputContext *context = + QGuiApplicationPrivate::platformIntegration()->inputContext(); + m_imeHasHiddenTextCapability = + context && context->hasCapability(QPlatformInputContext::HiddenTextCapability); +} + +Compositor::Id RenderWidgetHostViewQtDelegateClient::compositorId() +{ + return m_rwhv->compositorId(); +} + +void RenderWidgetHostViewQtDelegateClient::notifyShown() +{ + m_rwhv->notifyShown(); +} + +void RenderWidgetHostViewQtDelegateClient::notifyHidden() +{ + m_rwhv->notifyHidden(); +} + +void RenderWidgetHostViewQtDelegateClient::visualPropertiesChanged() +{ + RenderWidgetHostViewQtDelegate *delegate = m_rwhv->delegate(); + if (!delegate) + return; + + QRect oldViewRect = m_viewRectInDips; + m_viewRectInDips = delegate->viewGeometry().toAlignedRect(); + + QRect oldWindowRect = m_windowRectInDips; + m_windowRectInDips = delegate->windowGeometry(); + + bool screenInfoChanged = m_rwhv->updateScreenInfo(); + + if (m_viewRectInDips != oldViewRect || m_windowRectInDips != oldWindowRect) + m_rwhv->host()->SendScreenRects(); + + if (m_viewRectInDips.size() != oldViewRect.size() || screenInfoChanged) + m_rwhv->synchronizeVisualProperties(base::nullopt); +} + +bool RenderWidgetHostViewQtDelegateClient::forwardEvent(QEvent *event) +{ + Q_ASSERT(m_rwhv->host()->GetView()); + + switch (event->type()) { + case QEvent::ShortcutOverride: { + QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event); + + auto acceptKeyOutOfInputField = [](QKeyEvent *keyEvent) -> bool { +#ifdef Q_OS_MACOS + // Check if a shortcut is registered for this key sequence. + QKeySequence sequence = QKeySequence((keyEvent->modifiers() | keyEvent->key()) + & ~(Qt::KeypadModifier | Qt::GroupSwitchModifier)); + if (QGuiApplicationPrivate::instance()->shortcutMap.hasShortcutForKeySequence(sequence)) + return false; + + // The following shortcuts are handled out of input field too but + // disabled on macOS to let the blinking menu handling to the + // embedder application (see kKeyboardCodeKeyDownEntries in + // third_party/WebKit/Source/core/editing/EditingBehavior.cpp). + // Let them pass on macOS to generate the corresponding edit command. + return keyEvent->matches(QKeySequence::Copy) || keyEvent->matches(QKeySequence::Paste) + || keyEvent->matches(QKeySequence::Cut) + || keyEvent->matches(QKeySequence::SelectAll); +#else + return false; +#endif + }; + + if (!inputMethodQuery(Qt::ImEnabled).toBool() + && !(inputMethodQuery(Qt::ImHints).toInt() & Qt::ImhHiddenText) + && !acceptKeyOutOfInputField(keyEvent)) + return false; + + Q_ASSERT(m_editCommand.empty()); + if (WebEventFactory::getEditCommand(keyEvent, &m_editCommand) + || QInputControl::isCommonTextEditShortcut(keyEvent)) { + event->accept(); + return true; + } + + return false; + } + case QEvent::MouseButtonPress: + m_rwhv->Focus(); + Q_FALLTHROUGH(); + case QEvent::MouseButtonRelease: + case QEvent::MouseMove: + // Skip second MouseMove event when a window is being adopted, so that Chromium + // can properly handle further move events. + // Also make sure the adapter client exists to prevent a null pointer dereference, + // because it's possible for a QWebEnginePagePrivate (adapter) instance to be destroyed, + // and then the OS (observed on Windows) might still send mouse move events to a still + // existing popup RWHVQDW instance. + if (m_rwhv->adapterClient() && m_rwhv->adapterClient()->isBeingAdopted()) + return false; + handleMouseEvent(static_cast<QMouseEvent *>(event)); + break; + case QEvent::KeyPress: + case QEvent::KeyRelease: + handleKeyEvent(static_cast<QKeyEvent *>(event)); + break; + case QEvent::Wheel: + m_rwhv->handleWheelEvent(static_cast<QWheelEvent *>(event)); + break; + case QEvent::TouchBegin: + m_rwhv->Focus(); + Q_FALLTHROUGH(); + case QEvent::TouchUpdate: + case QEvent::TouchEnd: + case QEvent::TouchCancel: + handleTouchEvent(static_cast<QTouchEvent *>(event)); + break; +#if QT_CONFIG(tabletevent) + case QEvent::TabletPress: + m_rwhv->Focus(); + Q_FALLTHROUGH(); + case QEvent::TabletRelease: + case QEvent::TabletMove: + handleTabletEvent(static_cast<QTabletEvent *>(event)); + break; +#endif +#if QT_CONFIG(gestures) + case QEvent::NativeGesture: + handleGestureEvent(static_cast<QNativeGestureEvent *>(event)); + break; +#endif + case QEvent::HoverMove: + handleHoverEvent(static_cast<QHoverEvent *>(event)); + break; + case QEvent::FocusIn: + case QEvent::FocusOut: + handleFocusEvent(static_cast<QFocusEvent *>(event)); + break; + case QEvent::InputMethod: + handleInputMethodEvent(static_cast<QInputMethodEvent *>(event)); + break; + case QEvent::InputMethodQuery: + handleInputMethodQueryEvent(static_cast<QInputMethodQueryEvent *>(event)); + break; + case QEvent::Leave: +#ifdef Q_OS_WIN + if (m_mouseButtonPressed > 0) + return false; +#endif + case QEvent::HoverLeave: + m_rwhv->host()->ForwardMouseEvent(WebEventFactory::toWebMouseEvent(event)); + break; + default: + return false; + } + return true; +} + +QVariant RenderWidgetHostViewQtDelegateClient::inputMethodQuery(Qt::InputMethodQuery query) +{ + switch (query) { + case Qt::ImEnabled: { + ui::TextInputType type = m_rwhv->getTextInputType(); + bool editorVisible = type != ui::TEXT_INPUT_TYPE_NONE; + // IME manager should disable composition on input fields with ImhHiddenText hint if + // supported + if (m_imeHasHiddenTextCapability) + return QVariant(editorVisible); + + bool passwordInput = type == ui::TEXT_INPUT_TYPE_PASSWORD; + return QVariant(editorVisible && !passwordInput); + } + case Qt::ImFont: + // TODO: Implement this + return QVariant(); + case Qt::ImCursorRectangle: { + if (m_rwhv->GetTextInputManager()) { + if (auto *region = m_rwhv->GetTextInputManager()->GetSelectionRegion()) { + if (region->focus.GetHeight() > 0) { + gfx::Rect caretRect = + gfx::RectBetweenSelectionBounds(region->anchor, region->focus); + if (caretRect.width() == 0) + caretRect.set_width(1); // IME API on Windows expects a width > 0 + return toQt(caretRect); + } + } + } + return QVariant(); + } + case Qt::ImCursorPosition: + return m_cursorPosition; + case Qt::ImAnchorPosition: + return m_rwhv->GetSelectedText().empty() ? m_cursorPosition + : m_anchorPositionWithinSelection; + case Qt::ImSurroundingText: + return m_surroundingText; + case Qt::ImCurrentSelection: + return toQt(m_rwhv->GetSelectedText()); + case Qt::ImMaximumTextLength: + // TODO: Implement this + return QVariant(); // No limit. + case Qt::ImHints: +#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) + return int(toQtInputMethodHints(m_rwhv->getTextInputType()) | Qt::ImhNoPredictiveText + | Qt::ImhNoTextHandles | Qt::ImhNoEditMenu); +#else + return int(toQtInputMethodHints(m_rwhv->getTextInputType()) | Qt::ImhNoPredictiveText); +#endif + default: + return QVariant(); + } +} + +void RenderWidgetHostViewQtDelegateClient::closePopup() +{ + // We notify the popup to be closed by telling it that it lost focus. WebKit does the rest + // (hiding the widget and automatic memory cleanup via + // RenderWidget::CloseWidgetSoon() -> RenderWidgetHostImpl::ShutdownAndDestroyWidget(true). + m_rwhv->host()->SetActive(false); + m_rwhv->host()->LostFocus(); +} + +template<class T> +void RenderWidgetHostViewQtDelegateClient::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); + if ((webEvent.GetType() == blink::WebInputEvent::kMouseDown + || webEvent.GetType() == blink::WebInputEvent::kMouseUp) + && webEvent.button == blink::WebMouseEvent::Button::kNoButton) { + // Blink can only handle the 5 main mouse-buttons and may assert when processing mouse-down + // for no button. + LOG(INFO) << "Unhandled mouse button"; + return; + } + + if (webEvent.GetType() == blink::WebInputEvent::kMouseDown) { + if (event->button() != m_clickHelper.lastPressButton + || (event->timestamp() - m_clickHelper.lastPressTimestamp + > static_cast<ulong>(qGuiApp->styleHints()->mouseDoubleClickInterval())) + || (event->position() - m_clickHelper.lastPressPosition).manhattanLength() + > qGuiApp->styleHints()->startDragDistance() + || m_clickHelper.clickCounter >= 3) + m_clickHelper.clickCounter = 0; + + m_clickHelper.lastPressTimestamp = event->timestamp(); + webEvent.click_count = ++m_clickHelper.clickCounter; + m_clickHelper.lastPressButton = event->button(); + m_clickHelper.lastPressPosition = event->position().toPoint(); + } + + if (webEvent.GetType() == blink::WebInputEvent::kMouseUp) + webEvent.click_count = m_clickHelper.clickCounter; + + webEvent.movement_x = event->globalPosition().x() - m_previousMousePosition.x(); + webEvent.movement_y = event->globalPosition().y() - m_previousMousePosition.y(); + + if (m_rwhv->IsMouseLocked()) + QCursor::setPos(m_previousMousePosition); + else + m_previousMousePosition = event->globalPosition().toPoint(); + + if (m_imeInProgress && webEvent.GetType() == blink::WebInputEvent::kMouseDown) { + m_imeInProgress = false; + // Tell input method to commit the pre-edit string entered so far, and finish the + // composition operation. +#ifdef Q_OS_WIN + // Yes the function name is counter-intuitive, but commit isn't actually implemented + // by the Windows QPA, and reset does exactly what is necessary in this case. + qApp->inputMethod()->reset(); +#else + qApp->inputMethod()->commit(); +#endif + } + + m_rwhv->host()->ForwardMouseEvent(webEvent); +} + +void RenderWidgetHostViewQtDelegateClient::handleMouseEvent(QMouseEvent *event) +{ + if (event->type() == QEvent::MouseButtonPress) + m_mouseButtonPressed++; + if (event->type() == QEvent::MouseButtonRelease) + m_mouseButtonPressed--; + + // Don't forward mouse events synthesized by the system, which are caused by genuine touch + // events. Chromium would then process for e.g. a mouse click handler twice, once due to the + // system synthesized mouse event, and another time due to a touch-to-gesture-to-mouse + // transformation done by Chromium. + if (event->source() == Qt::MouseEventSynthesizedBySystem) + return; + handlePointerEvent<QMouseEvent>(event); +} + +void RenderWidgetHostViewQtDelegateClient::handleKeyEvent(QKeyEvent *event) +{ + if (m_rwhv->IsMouseLocked() && event->key() == Qt::Key_Escape + && event->type() == QEvent::KeyRelease) + m_rwhv->UnlockMouse(); + + if (m_receivedEmptyImeEvent) { + // IME composition was not finished with a valid commit string. + // We're getting the composition result in a key event. + if (event->key() != 0) { + // The key event is not a result of an IME composition. Cancel IME. + m_rwhv->host()->ImeCancelComposition(); + m_receivedEmptyImeEvent = false; + } else { + if (event->type() == QEvent::KeyRelease) { + m_rwhv->host()->ImeCommitText(toString16(event->text()), + std::vector<ui::ImeTextSpan>(), + gfx::Range::InvalidRange(), 0); + m_receivedEmptyImeEvent = false; + m_imeInProgress = false; + } + return; + } + } + + // Ignore autorepeating KeyRelease events so that the generated web events + // conform to the spec, which requires autorepeat to result in a sequence of + // keypress events and only one final keyup event: + // https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent#Auto-repeat_handling + // https://w3c.github.io/uievents/#dom-keyboardevent-repeat + if (event->type() == QEvent::KeyRelease && event->isAutoRepeat()) + return; + + content::NativeWebKeyboardEvent webEvent = WebEventFactory::toWebKeyboardEvent(event); + if (webEvent.GetType() == blink::WebInputEvent::kRawKeyDown && !m_editCommand.empty()) { + ui::LatencyInfo latency; + latency.set_source_event_type(ui::SourceEventType::KEY_PRESS); + content::EditCommands commands; + commands.emplace_back(m_editCommand, ""); + m_editCommand.clear(); + m_rwhv->host()->ForwardKeyboardEventWithCommands(webEvent, latency, &commands, nullptr); + return; + } + + bool keyDownTextInsertion = + webEvent.GetType() == blink::WebInputEvent::kRawKeyDown && webEvent.text[0]; + webEvent.skip_in_browser = keyDownTextInsertion; + m_rwhv->host()->ForwardKeyboardEvent(webEvent); + + if (keyDownTextInsertion) { + // Blink won't consume the RawKeyDown, but rather the Char event in this case. + // The RawKeyDown is skipped on the way back (see above). + // The same os_event will be set on both NativeWebKeyboardEvents. + webEvent.skip_in_browser = false; + webEvent.SetType(blink::WebInputEvent::kChar); + m_rwhv->host()->ForwardKeyboardEvent(webEvent); + } +} + +void RenderWidgetHostViewQtDelegateClient::handleTouchEvent(QTouchEvent *event) +{ + // On macOS instead of handling touch events, we use the OS provided QNativeGestureEvents. +#ifdef Q_OS_MACOS + if (event->spontaneous()) { + return; + } else { + VLOG(1) << "Sending simulated touch events to Chromium does not work properly on macOS. " + "Consider using QNativeGestureEvents or QMouseEvents."; + } +#endif + + // Chromium expects the touch event timestamps to be comparable to base::TimeTicks::Now(). + // Most importantly we also have to preserve the relative time distance between events. + // Calculate a delta between event timestamps and Now() on the first received event, and + // apply this delta to all successive events. This delta is most likely smaller than it + // should by calculating it here but this will hopefully cause less than one frame of delay. + base::TimeTicks eventTimestamp = + base::TimeTicks() + base::TimeDelta::FromMilliseconds(event->timestamp()); + static base::TimeDelta eventsToNowDelta = base::TimeTicks::Now() - eventTimestamp; + eventTimestamp += eventsToNowDelta; + + QList<QTouchEvent::TouchPoint> touchPoints = mapTouchPointIds(event->touchPoints()); + // Make sure that ACTION_POINTER_DOWN is delivered before ACTION_MOVE, + // and ACTION_MOVE before ACTION_POINTER_UP. + std::sort(touchPoints.begin(), touchPoints.end(), compareTouchPoints); + + // Check first if the touch event should be routed to the selectionController + if (!touchPoints.isEmpty()) { + 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, event->modifiers(), 0); + if (m_rwhv->getTouchSelectionController()->WillHandleTouchEvent(motionEvent)) { + m_previousTouchPoints = touchPoints; + event->accept(); + return; + } + } else { + // An empty touchPoints always corresponds to a TouchCancel event. + // We can't forward touch cancellations without a previously processed touch event, + // as Chromium expects the previous touchPoints for Action::CANCEL. + // If both are empty that means the TouchCancel was sent without an ongoing touch, + // so there's nothing to cancel anyway. + touchPoints = m_previousTouchPoints; + if (touchPoints.isEmpty()) + return; + + MotionEventQt cancelEvent(touchPoints, eventTimestamp, ui::MotionEvent::Action::CANCEL, + event->modifiers()); + if (m_rwhv->getTouchSelectionController()->WillHandleTouchEvent(cancelEvent)) { + m_previousTouchPoints.clear(); + event->accept(); + return; + } + } + + switch (event->type()) { + case QEvent::TouchBegin: + m_sendMotionActionDown = true; + m_touchMotionStarted = true; + m_rwhv->getTouchSelectionControllerClient()->onTouchDown(); + break; + case QEvent::TouchUpdate: + m_touchMotionStarted = true; + break; + case QEvent::TouchCancel: { + // Only process TouchCancel events received following a TouchBegin or TouchUpdate event + if (m_touchMotionStarted) { + MotionEventQt cancelEvent(touchPoints, eventTimestamp, ui::MotionEvent::Action::CANCEL, + event->modifiers()); + m_rwhv->processMotionEvent(cancelEvent); + } + + clearPreviousTouchMotionState(); + return; + } + case QEvent::TouchEnd: + clearPreviousTouchMotionState(); + m_rwhv->getTouchSelectionControllerClient()->onTouchUp(); + break; + default: + break; + } + + if (m_imeInProgress && event->type() == QEvent::TouchBegin) { + m_imeInProgress = false; + // Tell input method to commit the pre-edit string entered so far, and finish the + // composition operation. +#ifdef Q_OS_WIN + // Yes the function name is counter-intuitive, but commit isn't actually implemented + // by the Windows QPA, and reset does exactly what is necessary in this case. + qApp->inputMethod()->reset(); +#else + qApp->inputMethod()->commit(); +#endif + } + + for (int i = 0; i < touchPoints.size(); ++i) { + ui::MotionEvent::Action action; + switch (touchPoints[i].state()) { + case Qt::TouchPointPressed: + if (m_sendMotionActionDown) { + action = ui::MotionEvent::Action::DOWN; + m_sendMotionActionDown = false; + } else { + action = ui::MotionEvent::Action::POINTER_DOWN; + } + break; + case Qt::TouchPointMoved: + action = ui::MotionEvent::Action::MOVE; + break; + case Qt::TouchPointReleased: + action = touchPoints.size() > 1 ? ui::MotionEvent::Action::POINTER_UP + : ui::MotionEvent::Action::UP; + break; + default: + // Ignore Qt::TouchPointStationary + continue; + } + + MotionEventQt motionEvent(touchPoints, eventTimestamp, action, event->modifiers(), i); + m_rwhv->processMotionEvent(motionEvent); + } + + m_previousTouchPoints = touchPoints; +} + +#if QT_CONFIG(tabletevent) +void RenderWidgetHostViewQtDelegateClient::handleTabletEvent(QTabletEvent *event) +{ + handlePointerEvent<QTabletEvent>(event); +} +#endif + +#if QT_CONFIG(gestures) +void RenderWidgetHostViewQtDelegateClient::handleGestureEvent(QNativeGestureEvent *event) +{ + const Qt::NativeGestureType type = event->gestureType(); + // These are the only supported gestures by Chromium so far. + if (type == Qt::ZoomNativeGesture || type == Qt::SmartZoomNativeGesture) { + m_rwhv->host()->ForwardGestureEvent(WebEventFactory::toWebGestureEvent(event)); + } +} +#endif + +void RenderWidgetHostViewQtDelegateClient::handleHoverEvent(QHoverEvent *event) +{ + m_rwhv->host()->ForwardMouseEvent(WebEventFactory::toWebMouseEvent(event)); +} + +void RenderWidgetHostViewQtDelegateClient::handleFocusEvent(QFocusEvent *event) +{ + if (event->gotFocus()) { + m_rwhv->host()->GotFocus(); + m_rwhv->host()->SetActive(true); + content::RenderViewHostImpl *rvh = content::RenderViewHostImpl::From(m_rwhv->host()); + Q_ASSERT(rvh); + if (event->reason() == Qt::TabFocusReason) + rvh->SetInitialFocus(false); + else if (event->reason() == Qt::BacktabFocusReason) + rvh->SetInitialFocus(true); + event->accept(); + + m_rwhv->adapterClient()->webContentsAdapter()->handlePendingMouseLockPermission(); + } else if (event->lostFocus()) { + m_rwhv->host()->SetActive(false); + m_rwhv->host()->LostFocus(); + event->accept(); + } +} + +void RenderWidgetHostViewQtDelegateClient::handleInputMethodEvent(QInputMethodEvent *event) +{ + m_rwhv->resetInputManagerState(); + + if (!m_rwhv->host()) + return; + + QString commitString = event->commitString(); + QString preeditString = event->preeditString(); + + int cursorPositionInPreeditString = -1; + gfx::Range selectionRange = gfx::Range::InvalidRange(); + + const QList<QInputMethodEvent::Attribute> &attributes = event->attributes(); + std::vector<ui::ImeTextSpan> underlines; + bool hasSelection = false; + + for (const auto &attribute : attributes) { + switch (attribute.type) { + case QInputMethodEvent::TextFormat: { + if (preeditString.isEmpty()) + break; + + int start = qMin(attribute.start, (attribute.start + attribute.length)); + int end = qMax(attribute.start, (attribute.start + attribute.length)); + + // Blink does not support negative position values. Adjust start and end positions + // to non-negative values. + if (start < 0) { + start = 0; + end = qMax(0, start + end); + } + + underlines.push_back(ui::ImeTextSpan(ui::ImeTextSpan::Type::kComposition, start, end, + ui::ImeTextSpan::Thickness::kThin, + ui::ImeTextSpan::UnderlineStyle::kSolid, + SK_ColorTRANSPARENT)); + + QTextCharFormat format = qvariant_cast<QTextFormat>(attribute.value).toCharFormat(); + if (format.underlineStyle() != QTextCharFormat::NoUnderline) + underlines.back().underline_color = toSk(format.underlineColor()); + + break; + } + case QInputMethodEvent::Cursor: + // Always set the position of the cursor, even if it's marked invisible by Qt, otherwise + // there is no way the user will know which part of the composition string will be + // changed, when performing an IME-specific action (like selecting a different word + // suggestion). + cursorPositionInPreeditString = attribute.start; + break; + case QInputMethodEvent::Selection: + hasSelection = true; + + // Cancel IME composition + if (preeditString.isEmpty() && attribute.start + attribute.length == 0) { + selectionRange.set_start(0); + selectionRange.set_end(0); + break; + } + + selectionRange.set_start(qMin(attribute.start, (attribute.start + attribute.length))); + selectionRange.set_end(qMax(attribute.start, (attribute.start + attribute.length))); + break; + default: + break; + } + } + + if (!selectionRange.IsValid()) { + // We did not receive a valid selection range, hence the range is going to mark the + // cursor position. + int newCursorPosition = (cursorPositionInPreeditString < 0) ? preeditString.length() + : cursorPositionInPreeditString; + selectionRange.set_start(newCursorPosition); + selectionRange.set_end(newCursorPosition); + } + + if (hasSelection) { + content::mojom::FrameInputHandler *frameInputHandler = m_rwhv->getFrameInputHandler(); + if (frameInputHandler) + frameInputHandler->SetEditableSelectionOffsets(selectionRange.start(), + selectionRange.end()); + } + + int replacementLength = event->replacementLength(); + gfx::Range replacementRange = gfx::Range::InvalidRange(); + + if (replacementLength > 0) { + int replacementStart = event->replacementStart() < 0 + ? m_cursorPosition + event->replacementStart() + : event->replacementStart(); + if (replacementStart >= 0 && replacementStart < m_surroundingText.length()) + replacementRange = gfx::Range(replacementStart, replacementStart + replacementLength); + } + + // There are so-far two known cases, when an empty QInputMethodEvent is received. + // First one happens when backspace is used to remove the last character in the pre-edit + // string, thus signaling the end of the composition. + // The second one happens (on Windows) when a Korean char gets composed, but instead of + // the event having a commit string, both strings are empty, and the actual char is received + // as a QKeyEvent after the QInputMethodEvent is processed. + // In lieu of the second case, we can't simply cancel the composition on an empty event, + // and then add the Korean char when QKeyEvent is received, because that leads to text + // flickering in the textarea (or any other element). + // Instead we postpone the processing of the empty QInputMethodEvent by posting it + // to the same focused object, and cancelling the composition on the next event loop tick. + if (commitString.isEmpty() && preeditString.isEmpty() && replacementLength == 0) { + if (!m_receivedEmptyImeEvent && m_imeInProgress && !hasSelection) { + m_receivedEmptyImeEvent = true; + QInputMethodEvent *eventCopy = new QInputMethodEvent(*event); + QGuiApplication::postEvent(qApp->focusObject(), eventCopy); + } else { + m_receivedEmptyImeEvent = false; + if (m_imeInProgress) { + m_imeInProgress = false; + m_rwhv->host()->ImeCancelComposition(); + } + } + + return; + } + + m_receivedEmptyImeEvent = false; + + // Finish compostion: insert or erase text. + if (!commitString.isEmpty() || replacementLength > 0) { + m_rwhv->host()->ImeCommitText(toString16(commitString), underlines, replacementRange, 0); + m_imeInProgress = false; + } + + // Update or start new composition. + // Be aware of that, we might get a commit string and a pre-edit string in a single event and + // this means a new composition. + if (!preeditString.isEmpty()) { + m_rwhv->host()->ImeSetComposition(toString16(preeditString), underlines, replacementRange, + selectionRange.start(), selectionRange.end()); + m_imeInProgress = true; + } +} + +void RenderWidgetHostViewQtDelegateClient::handleInputMethodQueryEvent( + QInputMethodQueryEvent *event) +{ + Qt::InputMethodQueries queries = event->queries(); + for (uint i = 0; i < 32; ++i) { + Qt::InputMethodQuery query = (Qt::InputMethodQuery)(int)(queries & (1 << i)); + if (query) { + QVariant v = inputMethodQuery(query); + event->setValue(query, v); + } + } + event->accept(); +} + +void RenderWidgetHostViewQtDelegateClient::clearPreviousTouchMotionState() +{ + m_previousTouchPoints.clear(); + m_touchMotionStarted = false; +} + +void RenderWidgetHostViewQtDelegateClient::selectionChanged() +{ + m_rwhv->resetInputManagerState(); + ui::TextInputType type = m_rwhv->getTextInputType(); + content::TextInputManager *text_input_manager = m_rwhv->GetTextInputManager(); + + // Handle text selection out of an input field + if (type == ui::TEXT_INPUT_TYPE_NONE) { + if (m_rwhv->GetSelectedText().empty() && m_emptyPreviousSelection) + return; + + // Reset position values to emit selectionChanged signal when clearing text selection + // by clicking into an input field. These values are intended to be used by inputMethodQuery + // so they are not expected to be valid when selection is out of an input field. + m_anchorPositionWithinSelection = -1; + m_cursorPositionWithinSelection = -1; + + m_emptyPreviousSelection = m_rwhv->GetSelectedText().empty(); + m_rwhv->adapterClient()->selectionChanged(); + return; + } + + if (m_rwhv->GetSelectedText().empty()) { + // RenderWidgetHostViewQt::OnUpdateTextInputStateCalled() does not update the cursor + // position if the selection is cleared because TextInputState changes before the + // TextSelection change. + Q_ASSERT(text_input_manager->GetTextInputState()); + m_cursorPosition = text_input_manager->GetTextInputState()->selection_start; + m_rwhv->delegate()->inputMethodStateChanged(true /*editorVisible*/, + type == ui::TEXT_INPUT_TYPE_PASSWORD); + + m_anchorPositionWithinSelection = m_cursorPosition; + m_cursorPositionWithinSelection = m_cursorPosition; + + if (!m_emptyPreviousSelection) { + m_emptyPreviousSelection = true; + m_rwhv->adapterClient()->selectionChanged(); + } + + return; + } + + const content::TextInputManager::TextSelection *selection = + text_input_manager->GetTextSelection(); + if (!selection) + return; + + if (!selection->range().IsValid()) + return; + + int newAnchorPositionWithinSelection = 0; + int newCursorPositionWithinSelection = 0; + + if (text_input_manager->GetSelectionRegion()->anchor.type() == gfx::SelectionBound::RIGHT) { + newAnchorPositionWithinSelection = selection->range().GetMax() - selection->offset(); + newCursorPositionWithinSelection = selection->range().GetMin() - selection->offset(); + } else { + newAnchorPositionWithinSelection = selection->range().GetMin() - selection->offset(); + newCursorPositionWithinSelection = selection->range().GetMax() - selection->offset(); + } + + if (m_anchorPositionWithinSelection == newAnchorPositionWithinSelection + && m_cursorPositionWithinSelection == newCursorPositionWithinSelection) { + return; + } + + m_anchorPositionWithinSelection = newAnchorPositionWithinSelection; + m_cursorPositionWithinSelection = newCursorPositionWithinSelection; + + if (!selection->selected_text().empty()) + m_cursorPosition = newCursorPositionWithinSelection; + + m_emptyPreviousSelection = selection->selected_text().empty(); + m_rwhv->delegate()->inputMethodStateChanged(true /*editorVisible*/, + type == ui::TEXT_INPUT_TYPE_PASSWORD); + m_rwhv->adapterClient()->selectionChanged(); +} + +} // namespace QtWebEngineCore diff --git a/src/core/render_widget_host_view_qt_delegate_client.h b/src/core/render_widget_host_view_qt_delegate_client.h new file mode 100644 index 000000000..c338df95e --- /dev/null +++ b/src/core/render_widget_host_view_qt_delegate_client.h @@ -0,0 +1,164 @@ +/**************************************************************************** +** +** Copyright (C) 2020 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 RENDER_WIDGET_HOST_VIEW_QT_DELEGATE_CLIENT_H +#define RENDER_WIDGET_HOST_VIEW_QT_DELEGATE_CLIENT_H + +#include "compositor/compositor.h" + +#include <QtGui/QCursor> +#include <QtGui/QTouchEvent> + +QT_BEGIN_NAMESPACE +class QEvent; +class QVariant; +class QMouseEvent; +class QKeyEvent; +class QTabletEvent; +class QNativeGestureEvent; +class QHoverEvent; +class QFocusEvent; +class QInputMethodEvent; +class QInputMethodQueryEvent; +QT_END_NAMESPACE + +namespace QtWebEngineCore { + +class RenderWidgetHostViewQt; + +struct MultipleMouseClickHelper +{ + QPoint lastPressPosition; + Qt::MouseButton lastPressButton = Qt::NoButton; + int clickCounter = 0; + ulong lastPressTimestamp = 0; +}; + +class Q_WEBENGINECORE_PRIVATE_EXPORT RenderWidgetHostViewQtDelegateClient +{ +public: + RenderWidgetHostViewQtDelegateClient(RenderWidgetHostViewQt *rwhv); + + Compositor::Id compositorId(); + void notifyShown(); + void notifyHidden(); + void visualPropertiesChanged(); + bool forwardEvent(QEvent *); + QVariant inputMethodQuery(Qt::InputMethodQuery query); + void closePopup(); + +private: + friend class RenderWidgetHostViewQt; + + template<class T> + void handlePointerEvent(T *); + void handleMouseEvent(QMouseEvent *); + void handleKeyEvent(QKeyEvent *); + void handleTouchEvent(QTouchEvent *); +#if QT_CONFIG(tabletevent) + void handleTabletEvent(QTabletEvent *); +#endif +#if QT_CONFIG(gestures) + void handleGestureEvent(QNativeGestureEvent *); +#endif + void handleHoverEvent(QHoverEvent *); + void handleFocusEvent(QFocusEvent *); + void handleInputMethodEvent(QInputMethodEvent *); + void handleInputMethodQueryEvent(QInputMethodQueryEvent *); + + QRect viewRectInDips() const { return m_viewRectInDips; } + QRect windowRectInDips() const { return m_windowRectInDips; } + + // Mouse + void resetPreviousMousePosition() { m_previousMousePosition = QCursor::pos(); } + + // Touch + void clearPreviousTouchMotionState(); + + // IME + void selectionChanged(); + void setCursorPosition(uint pos) { m_cursorPosition = pos; } + void setSurroundingText(const QString &text) { m_surroundingText = text; } + bool isPreviousSelectionEmpty() const { return m_emptyPreviousSelection; } + + RenderWidgetHostViewQt *m_rwhv; + + // Mouse + bool m_imeHasHiddenTextCapability; + uint m_mouseButtonPressed = 0; + QPoint m_previousMousePosition; + MultipleMouseClickHelper m_clickHelper; + + // Key + std::string m_editCommand; + + // Touch + QList<QTouchEvent::TouchPoint> m_previousTouchPoints; + bool m_touchMotionStarted = false; + bool m_sendMotionActionDown = false; + + // IME + bool m_receivedEmptyImeEvent = false; + bool m_imeInProgress = false; + bool m_emptyPreviousSelection = true; + uint m_cursorPosition = 0; + int m_anchorPositionWithinSelection = -1; + int m_cursorPositionWithinSelection = -1; + QString m_surroundingText; + + // Geometry of the view in screen DIPs. + QRect m_viewRectInDips; + // Geometry of the window, including frame, in screen DIPs. + QRect m_windowRectInDips; +}; + +} // namespace QtWebEngineCore + +#endif // RENDER_WIDGET_HOST_VIEW_QT_DELEGATE_CLIENT_H diff --git a/src/core/renderer/content_renderer_client_qt.cpp b/src/core/renderer/content_renderer_client_qt.cpp index 9f1f5bcf3..8c70f2e42 100644 --- a/src/core/renderer/content_renderer_client_qt.cpp +++ b/src/core/renderer/content_renderer_client_qt.cpp @@ -293,7 +293,7 @@ void ContentRendererClientQt::GetNavigationErrorStringsInternal(content::RenderF const error_page::Error &error, std::string *errorHtml) { - Q_UNUSED(renderFrame) + Q_UNUSED(renderFrame); const bool isPost = QByteArray::fromStdString(httpMethod) == QByteArrayLiteral("POST"); if (errorHtml) { diff --git a/src/core/renderer/user_resource_controller.cpp b/src/core/renderer/user_resource_controller.cpp index 5c1bd301f..3c1ad0477 100644 --- a/src/core/renderer/user_resource_controller.cpp +++ b/src/core/renderer/user_resource_controller.cpp @@ -197,8 +197,8 @@ void UserResourceController::runScripts(UserScriptData::InjectionPoint p, blink: if (!renderView) return; - QList<uint64_t> scriptsToRun = m_viewUserScriptMap.value(0).toList(); - scriptsToRun.append(m_viewUserScriptMap.value(renderView).toList()); + QList<uint64_t> scriptsToRun = m_viewUserScriptMap.value(0).values(); + scriptsToRun.append(m_viewUserScriptMap.value(renderView).values()); for (uint64_t id : qAsConst(scriptsToRun)) { const UserScriptData &script = m_scripts.value(id); diff --git a/src/core/renderer/web_channel_ipc_transport.cpp b/src/core/renderer/web_channel_ipc_transport.cpp index 1fb3bc678..496417329 100644 --- a/src/core/renderer/web_channel_ipc_transport.cpp +++ b/src/core/renderer/web_channel_ipc_transport.cpp @@ -152,22 +152,13 @@ void WebChannelTransport::NativeQtSendMessage(gin::Arguments *args) return; } v8::Local<v8::String> jsonString = v8::Local<v8::String>::Cast(jsonValue); + std::vector<uint8_t> json(jsonString->Utf8Length(isolate), 0); + jsonString->WriteUtf8(isolate, reinterpret_cast<char *>(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); - if (error.error != QJsonParseError::NoError) { - args->ThrowTypeError("Invalid JSON"); - return; - } - - int size = 0; - const char *rawData = doc.rawData(&size); mojo::AssociatedRemote<qtwebchannel::mojom::WebChannelTransportHost> webChannelTransport; renderFrame->GetRemoteAssociatedInterfaces()->GetInterface(&webChannelTransport); - webChannelTransport->DispatchWebChannelMessage(std::vector<uint8_t>(rawData, rawData + size)); + webChannelTransport->DispatchWebChannelMessage(json); } gin::ObjectTemplateBuilder WebChannelTransport::GetObjectTemplateBuilder(v8::Isolate *isolate) @@ -213,18 +204,14 @@ void WebChannelIPCTransport::ResetWorldId() m_worldId = 0; } -void WebChannelIPCTransport::DispatchWebChannelMessage(const std::vector<uint8_t> &binaryJson, uint32_t worldId) +void WebChannelIPCTransport::DispatchWebChannelMessage(const std::vector<uint8_t> &json, + uint32_t worldId) { DCHECK(m_worldId == worldId); if (!m_canUseContext) return; - QJsonDocument doc = QJsonDocument::fromRawData(reinterpret_cast<const char *>(binaryJson.data()), binaryJson.size(), - QJsonDocument::BypassValidation); - DCHECK(doc.isObject()); - QByteArray json = doc.toJson(QJsonDocument::Compact); - blink::WebLocalFrame *frame = render_frame()->GetWebFrame(); v8::Isolate *isolate = blink::MainThreadIsolate(); v8::HandleScope handleScope(isolate); @@ -255,7 +242,9 @@ void WebChannelIPCTransport::DispatchWebChannelMessage(const std::vector<uint8_t v8::Local<v8::Object> messageObject(v8::Object::New(isolate)); v8::Maybe<bool> wasSet = messageObject->DefineOwnProperty( context, v8::String::NewFromUtf8(isolate, "data").ToLocalChecked(), - v8::String::NewFromUtf8(isolate, json.constData(), v8::NewStringType::kNormal, json.size()).ToLocalChecked(), + v8::String::NewFromUtf8(isolate, reinterpret_cast<const char *>(json.data()), + v8::NewStringType::kNormal, json.size()) + .ToLocalChecked(), v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete)); DCHECK(!wasSet.IsNothing() && wasSet.FromJust()); diff --git a/src/core/renderer/web_channel_ipc_transport.h b/src/core/renderer/web_channel_ipc_transport.h index 15778a7bc..7c3b21eec 100644 --- a/src/core/renderer/web_channel_ipc_transport.h +++ b/src/core/renderer/web_channel_ipc_transport.h @@ -61,7 +61,7 @@ private: // qtwebchannel::mojom::WebChannelTransportRender void SetWorldId(uint32_t worldId) override; void ResetWorldId() override; - void DispatchWebChannelMessage(const std::vector<uint8_t> &binaryJson, uint32_t worldId) override; + void DispatchWebChannelMessage(const std::vector<uint8_t> &json, uint32_t worldId) override; // RenderFrameObserver void WillReleaseScriptContext(v8::Local<v8::Context> context, int worldId) override; diff --git a/src/core/renderer_host/user_resource_controller_host.cpp b/src/core/renderer_host/user_resource_controller_host.cpp index 6b9bb63fe..0c0818ba9 100644 --- a/src/core/renderer_host/user_resource_controller_host.cpp +++ b/src/core/renderer_host/user_resource_controller_host.cpp @@ -116,8 +116,6 @@ void UserResourceControllerHost::RenderProcessObserverHelper::RenderProcessHostD void UserResourceControllerHost::addUserScript(const UserScript &script, WebContentsAdapter *adapter) { - if (script.isNull()) - return; // Global scripts should be dispatched to all our render processes. const bool isProfileWideScript = !adapter; if (isProfileWideScript) { @@ -150,8 +148,6 @@ void UserResourceControllerHost::addUserScript(const UserScript &script, WebCont bool UserResourceControllerHost::removeUserScript(const UserScript &script, WebContentsAdapter *adapter) { - if (script.isNull()) - return false; const bool isProfileWideScript = !adapter; if (isProfileWideScript) { QList<UserScript>::iterator it = std::find(m_profileWideScripts.begin(), m_profileWideScripts.end(), script); diff --git a/src/core/renderer_host/user_resource_controller_host.h b/src/core/renderer_host/user_resource_controller_host.h index 7b89cb893..76954e0cc 100644 --- a/src/core/renderer_host/user_resource_controller_host.h +++ b/src/core/renderer_host/user_resource_controller_host.h @@ -64,6 +64,7 @@ class WebContents; namespace QtWebEngineCore { +class UserScript; class WebContentsAdapter; class Q_WEBENGINECORE_PRIVATE_EXPORT UserResourceControllerHost diff --git a/src/core/renderer_host/web_channel_ipc_transport_host.cpp b/src/core/renderer_host/web_channel_ipc_transport_host.cpp index 9ed3749ad..5d4356533 100644 --- a/src/core/renderer_host/web_channel_ipc_transport_host.cpp +++ b/src/core/renderer_host/web_channel_ipc_transport_host.cpp @@ -93,13 +93,13 @@ uint WebChannelIPCTransportHost::worldId() const void WebChannelIPCTransportHost::sendMessage(const QJsonObject &message) { QJsonDocument doc(message); - int size = 0; - const char *rawData = doc.rawData(&size); + QByteArray json = doc.toJson(QJsonDocument::Compact); content::RenderFrameHost *frame = web_contents()->GetMainFrame(); mojo::AssociatedRemote<qtwebchannel::mojom::WebChannelTransportRender> webChannelTransport; frame->GetRemoteAssociatedInterfaces()->GetInterface(&webChannelTransport); qCDebug(log).nospace() << "sending webchannel message to " << frame << ": " << doc; - webChannelTransport->DispatchWebChannelMessage(std::vector<uint8_t>(rawData, rawData + size), m_worldId); + webChannelTransport->DispatchWebChannelMessage(std::vector<uint8_t>(json.begin(), json.end()), + m_worldId); } void WebChannelIPCTransportHost::setWorldId(uint32_t worldId) @@ -132,7 +132,7 @@ void WebChannelIPCTransportHost::resetWorldId() } } -void WebChannelIPCTransportHost::DispatchWebChannelMessage(const std::vector<uint8_t> &binaryJson) +void WebChannelIPCTransportHost::DispatchWebChannelMessage(const std::vector<uint8_t> &json) { content::RenderFrameHost *frame = web_contents()->GetMainFrame(); @@ -140,7 +140,8 @@ void WebChannelIPCTransportHost::DispatchWebChannelMessage(const std::vector<uin return; } - QJsonDocument doc = QJsonDocument::fromRawData(reinterpret_cast<const char *>(binaryJson.data()), binaryJson.size()); + QJsonDocument doc = QJsonDocument::fromJson( + QByteArray(reinterpret_cast<const char *>(json.data()), json.size())); if (!doc.isObject()) { qCCritical(log).nospace() << "received invalid webchannel message from " << frame; diff --git a/src/core/renderer_host/web_channel_ipc_transport_host.h b/src/core/renderer_host/web_channel_ipc_transport_host.h index a1575355a..3d15082b8 100644 --- a/src/core/renderer_host/web_channel_ipc_transport_host.h +++ b/src/core/renderer_host/web_channel_ipc_transport_host.h @@ -70,13 +70,12 @@ public: private: void setWorldId(content::RenderFrameHost *frame, uint32_t worldId); void resetWorldId(); - void onWebChannelMessage(const std::vector<char> &message); // WebContentsObserver void RenderFrameCreated(content::RenderFrameHost *frame) override; // qtwebchannel::mojom::WebChannelTransportHost - void DispatchWebChannelMessage(const std::vector<uint8_t> &binaryJson) override; + void DispatchWebChannelMessage(const std::vector<uint8_t> &json) override; // Empty only during construction/destruction. Synchronized to all the // WebChannelIPCTransports/RenderFrames in the observed WebContents. diff --git a/src/core/type_conversion.cpp b/src/core/type_conversion.cpp index 1d8d63257..bf2656de4 100644 --- a/src/core/type_conversion.cpp +++ b/src/core/type_conversion.cpp @@ -296,4 +296,40 @@ QList<QSslCertificate> toCertificateChain(net::X509Certificate *certificate) return chain; } +Qt::InputMethodHints toQtInputMethodHints(ui::TextInputType inputType) +{ + switch (inputType) { + case ui::TEXT_INPUT_TYPE_TEXT: + return Qt::ImhPreferLowercase; + case ui::TEXT_INPUT_TYPE_SEARCH: + return Qt::ImhPreferLowercase | Qt::ImhNoAutoUppercase; + case ui::TEXT_INPUT_TYPE_PASSWORD: + return Qt::ImhSensitiveData | Qt::ImhNoPredictiveText | Qt::ImhNoAutoUppercase + | Qt::ImhHiddenText; + case ui::TEXT_INPUT_TYPE_EMAIL: + return Qt::ImhEmailCharactersOnly; + case ui::TEXT_INPUT_TYPE_NUMBER: + return Qt::ImhFormattedNumbersOnly; + case ui::TEXT_INPUT_TYPE_TELEPHONE: + return Qt::ImhDialableCharactersOnly; + case ui::TEXT_INPUT_TYPE_URL: + return Qt::ImhUrlCharactersOnly | Qt::ImhNoPredictiveText | Qt::ImhNoAutoUppercase; + case ui::TEXT_INPUT_TYPE_DATE_TIME: + case ui::TEXT_INPUT_TYPE_DATE_TIME_LOCAL: + case ui::TEXT_INPUT_TYPE_DATE_TIME_FIELD: + return Qt::ImhDate | Qt::ImhTime; + case ui::TEXT_INPUT_TYPE_DATE: + case ui::TEXT_INPUT_TYPE_MONTH: + case ui::TEXT_INPUT_TYPE_WEEK: + return Qt::ImhDate; + case ui::TEXT_INPUT_TYPE_TIME: + return Qt::ImhTime; + case ui::TEXT_INPUT_TYPE_TEXT_AREA: + case ui::TEXT_INPUT_TYPE_CONTENT_EDITABLE: + return Qt::ImhMultiLine | Qt::ImhPreferLowercase; + default: + return Qt::ImhNone; + } +} + } // namespace QtWebEngineCore diff --git a/src/core/type_conversion.h b/src/core/type_conversion.h index 83a499284..565d8330a 100644 --- a/src/core/type_conversion.h +++ b/src/core/type_conversion.h @@ -60,6 +60,7 @@ #include "third_party/skia/include/core/SkColor.h" #include "third_party/skia/include/core/SkPixelRef.h" #include "third_party/skia/include/core/SkMatrix44.h" +#include "ui/base/ime/text_input_type.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/rect_f.h" #include "url/gurl.h" @@ -80,9 +81,9 @@ namespace QtWebEngineCore { inline QString toQt(const base::string16 &string) { #if defined(OS_WIN) - return QString::fromStdWString(string.data()); + return QString::fromStdWString(string); #else - return QString::fromUtf16(string.data()); + return QString::fromUtf16(reinterpret_cast<const char16_t *>(string.data()), string.size()); #endif } @@ -295,6 +296,8 @@ FaviconInfo toFaviconInfo(const blink::mojom::FaviconURLPtr &favicon_url); QList<QSslCertificate> toCertificateChain(net::X509Certificate *certificate); +Qt::InputMethodHints toQtInputMethodHints(ui::TextInputType inputType); + } // namespace QtWebEngineCore #endif // TYPE_CONVERSION_H diff --git a/src/core/user_script.cpp b/src/core/user_script.cpp index 912b204b7..f4f320d4c 100644 --- a/src/core/user_script.cpp +++ b/src/core/user_script.cpp @@ -74,28 +74,15 @@ UserScript::UserScript() { } -UserScript::UserScript(const UserScript &other) - : QSharedData(other) -{ - if (other.isNull()) - return; - scriptData.reset(new UserScriptData(*other.scriptData)); - m_name = other.m_name; -} +UserScript::UserScript(const UserScript &other) = default; -UserScript::~UserScript() -{ -} +UserScript::~UserScript() = default; UserScript &UserScript::operator=(const UserScript &other) { - if (other.isNull()) { - scriptData.reset(); - m_name = QString(); - return *this; - } - scriptData.reset(new UserScriptData(*other.scriptData)); + m_scriptData = other.m_scriptData; m_name = other.m_name; + m_url = other.m_url; return *this; } @@ -107,101 +94,82 @@ QString UserScript::name() const void UserScript::setName(const QString &name) { m_name = name; - initData(); - scriptData->url = GURL(QStringLiteral("userScript:%1").arg(name).toStdString()); + m_scriptData.url = GURL(QStringLiteral("userScript:%1").arg(name).toStdString()); } QString UserScript::sourceCode() const { - if (isNull()) - return QString(); - return toQt(scriptData->source); + return toQt(m_scriptData.source); } void UserScript::setSourceCode(const QString &source) { - initData(); - scriptData->source = source.toStdString(); + m_scriptData.source = source.toStdString(); parseMetadataHeader(); } -UserScript::InjectionPoint UserScript::injectionPoint() const +QUrl UserScript::sourceUrl() const { - if (isNull()) - return UserScript::AfterLoad; - return static_cast<UserScript::InjectionPoint>(scriptData->injectionPoint); + return m_url; } -void UserScript::setInjectionPoint(UserScript::InjectionPoint p) +void UserScript::setSourceUrl(const QUrl &url) { - initData(); - scriptData->injectionPoint = p; + m_url = url; } -uint UserScript::worldId() const +UserScript::InjectionPoint UserScript::injectionPoint() const { - if (isNull()) - return 1; - return scriptData->worldId; + return static_cast<UserScript::InjectionPoint>(m_scriptData.injectionPoint); } -void UserScript::setWorldId(uint id) +void UserScript::setInjectionPoint(UserScript::InjectionPoint p) { - initData(); - scriptData->worldId = id; + m_scriptData.injectionPoint = p; } -bool UserScript::runsOnSubFrames() const +quint32 UserScript::worldId() const { - if (isNull()) - return false; - return scriptData->injectForSubframes; + return m_scriptData.worldId; } -void UserScript::setRunsOnSubFrames(bool on) +void UserScript::setWorldId(quint32 id) { - initData(); - scriptData->injectForSubframes = on; + m_scriptData.worldId = id; } -bool UserScript::operator==(const UserScript &other) const +bool UserScript::runsOnSubFrames() const { - if (isNull() != other.isNull()) - return false; - if (isNull()) // neither is valid - return true; - return worldId() == other.worldId() - && runsOnSubFrames() == other.runsOnSubFrames() - && injectionPoint() == other.injectionPoint() - && name() == other.name() && sourceCode() == other.sourceCode(); + return m_scriptData.injectForSubframes; } -void UserScript::initData() +void UserScript::setRunsOnSubFrames(bool on) { - if (scriptData.isNull()) - scriptData.reset(new UserScriptData); + m_scriptData.injectForSubframes = on; } -bool UserScript::isNull() const +const UserScriptData &UserScript::data() const { - return scriptData.isNull(); + return m_scriptData; } -UserScriptData &UserScript::data() const +bool UserScript::operator==(const UserScript &other) const { - return *(scriptData.data()); + return worldId() == other.worldId() && runsOnSubFrames() == other.runsOnSubFrames() + && injectionPoint() == other.injectionPoint() && name() == other.name() + && sourceCode() == other.sourceCode() && sourceUrl() == other.sourceUrl(); } void UserScript::parseMetadataHeader() { // Clear previous values - scriptData->globs.clear(); - scriptData->excludeGlobs.clear(); - scriptData->urlPatterns.clear(); + m_scriptData.globs.clear(); + m_scriptData.excludeGlobs.clear(); + m_scriptData.urlPatterns.clear(); // Logic taken from Chromium (extensions/browser/user_script_loader.cc) // http://wiki.greasespot.net/Metadata_block - const std::string &script_text = scriptData->source; + const std::string &script_text = m_scriptData.source; base::StringPiece line; size_t line_start = 0; size_t line_end = line_start; @@ -247,7 +215,7 @@ void UserScript::parseMetadataHeader() base::ReplaceSubstringsAfterOffset(&value, 0, "\\", "\\\\"); base::ReplaceSubstringsAfterOffset(&value, 0, "?", "\\?"); } - scriptData->globs.push_back(value); + m_scriptData.globs.push_back(value); } else if (GetDeclarationValue(line, kExcludeDeclaration, &value)) { if (value.front() != '/' || value.back() != '/') { // The greasemonkey spec only allows for wildcards (*), so @@ -255,16 +223,16 @@ void UserScript::parseMetadataHeader() base::ReplaceSubstringsAfterOffset(&value, 0, "\\", "\\\\"); base::ReplaceSubstringsAfterOffset(&value, 0, "?", "\\?"); } - scriptData->excludeGlobs.push_back(value); + m_scriptData.excludeGlobs.push_back(value); } else if (GetDeclarationValue(line, kMatchDeclaration, &value)) { - scriptData->urlPatterns.push_back(value); + m_scriptData.urlPatterns.push_back(value); } else if (GetDeclarationValue(line, kRunAtDeclaration, &value)) { if (value == kRunAtDocumentStartValue) - scriptData->injectionPoint = DocumentElementCreation; + m_scriptData.injectionPoint = DocumentElementCreation; else if (value == kRunAtDocumentEndValue) - scriptData->injectionPoint = DocumentLoadFinished; + m_scriptData.injectionPoint = DocumentLoadFinished; else if (value == kRunAtDocumentIdleValue) - scriptData->injectionPoint = AfterLoad; + m_scriptData.injectionPoint = AfterLoad; } } @@ -273,8 +241,8 @@ void UserScript::parseMetadataHeader() // If no patterns were specified, default to @include *. This is what // Greasemonkey does. - if (scriptData->globs.empty() && scriptData->urlPatterns.empty()) - scriptData->globs.push_back("*"); + if (m_scriptData.globs.empty() && m_scriptData.urlPatterns.empty()) + m_scriptData.globs.push_back("*"); } } // namespace QtWebEngineCore diff --git a/src/core/user_script.h b/src/core/user_script.h index 8f65f4b74..4970641e1 100644 --- a/src/core/user_script.h +++ b/src/core/user_script.h @@ -52,10 +52,11 @@ #define USER_SCRIPT_H #include "qtwebenginecoreglobal_p.h" - +#include "common/user_script_data.h" #include <QtCore/QScopedPointer> #include <QtCore/QSharedData> #include <QtCore/QString> +#include <QtCore/QUrl> struct UserScriptData; @@ -63,7 +64,8 @@ namespace QtWebEngineCore { class UserResourceControllerHost; -class Q_WEBENGINECORE_PRIVATE_EXPORT UserScript : public QSharedData { +class UserScript : public QSharedData +{ public: enum InjectionPoint { AfterLoad, @@ -76,19 +78,20 @@ public: ~UserScript(); UserScript &operator=(const UserScript &other); - bool isNull() const; - QString name() const; void setName(const QString &); QString sourceCode() const; void setSourceCode(const QString &); + QUrl sourceUrl() const; + void setSourceUrl(const QUrl &); + InjectionPoint injectionPoint() const; void setInjectionPoint(InjectionPoint); - uint worldId() const; - void setWorldId(uint id); + quint32 worldId() const; + void setWorldId(quint32 id); bool runsOnSubFrames() const; void setRunsOnSubFrames(bool on); @@ -96,13 +99,13 @@ public: bool operator==(const UserScript &) const; private: - void initData(); - UserScriptData &data() const; + const UserScriptData &data() const; void parseMetadataHeader(); friend class UserResourceControllerHost; - QScopedPointer<UserScriptData> scriptData; + UserScriptData m_scriptData; QString m_name; + QUrl m_url; }; } // namespace QtWebEngineCore diff --git a/src/core/visited_links_manager_qt.h b/src/core/visited_links_manager_qt.h index c4e24ce1f..27d46f8ff 100644 --- a/src/core/visited_links_manager_qt.h +++ b/src/core/visited_links_manager_qt.h @@ -55,9 +55,7 @@ #include <QList> #include <QScopedPointer> -QT_BEGIN_NAMESPACE -class QUrl; -QT_END_NAMESPACE +QT_FORWARD_DECLARE_CLASS(QUrl) namespace visitedlink { class VisitedLinkWriter; diff --git a/src/core/web_contents_adapter.cpp b/src/core/web_contents_adapter.cpp index a44b3316e..db2069fe7 100644 --- a/src/core/web_contents_adapter.cpp +++ b/src/core/web_contents_adapter.cpp @@ -117,6 +117,7 @@ #include <QtCore/qmimedata.h> #include <QtCore/qtemporarydir.h> #include <QtGui/qdrag.h> +#include <QtGui/QDragEnterEvent> #include <QtGui/qpixmap.h> // Can't include headers as qaccessible.h conflicts with Chromium headers. @@ -487,7 +488,7 @@ void WebContentsAdapter::setClient(WebContentsAdapterClient *adapterClient) Q_ASSERT(m_profileAdapter); // This might replace any adapter that has been initialized with this WebEngineSettings. - adapterClient->webEngineSettings()->setWebContentsAdapter(this); + WebEngineSettings::get(adapterClient->webEngineSettings())->setWebContentsAdapter(this); } bool WebContentsAdapter::isInitialized() const @@ -565,7 +566,8 @@ void WebContentsAdapter::initializeRenderPrefs() commandLine->GetSwitchValueASCII(switches::kForceWebRtcIPHandlingPolicy); else rendererPrefs->webrtc_ip_handling_policy = - m_adapterClient->webEngineSettings()->testAttribute(WebEngineSettings::WebRTCPublicInterfacesOnly) + m_adapterClient->webEngineSettings()->testAttribute( + QWebEngineSettings::WebRTCPublicInterfacesOnly) ? blink::kWebRTCIPHandlingDefaultPublicInterfaceOnly : blink::kWebRTCIPHandlingDefault; #endif @@ -618,7 +620,7 @@ void WebContentsAdapter::reload() bool wasDiscarded = (m_lifecycleState == LifecycleState::Discarded); setLifecycleState(LifecycleState::Active); CHECK_VALID_RENDER_WIDGET_HOST_VIEW(m_webContents->GetRenderViewHost()); - WebEngineSettings *settings = m_adapterClient->webEngineSettings(); + WebEngineSettings *settings = WebEngineSettings::get(m_adapterClient->webEngineSettings()); settings->doApply(); if (!wasDiscarded) // undiscard() already triggers a reload m_webContents->GetController().Reload(content::ReloadType::NORMAL, /*checkRepost = */false); @@ -631,7 +633,7 @@ void WebContentsAdapter::reloadAndBypassCache() bool wasDiscarded = (m_lifecycleState == LifecycleState::Discarded); setLifecycleState(LifecycleState::Active); CHECK_VALID_RENDER_WIDGET_HOST_VIEW(m_webContents->GetRenderViewHost()); - WebEngineSettings *settings = m_adapterClient->webEngineSettings(); + WebEngineSettings *settings = WebEngineSettings::get(m_adapterClient->webEngineSettings()); settings->doApply(); if (!wasDiscarded) // undiscard() already triggers a reload m_webContents->GetController().Reload(content::ReloadType::BYPASSING_CACHE, /*checkRepost = */false); @@ -663,8 +665,7 @@ void WebContentsAdapter::load(const QWebEngineHttpRequest &request) CHECK_VALID_RENDER_WIDGET_HOST_VIEW(m_webContents->GetRenderViewHost()); - WebEngineSettings *settings = m_adapterClient->webEngineSettings(); - settings->doApply(); + WebEngineSettings::get(m_adapterClient->webEngineSettings())->doApply(); // The situation can occur when relying on the editingFinished signal in QML to set the url // of the WebView. @@ -718,8 +719,8 @@ void WebContentsAdapter::load(const QWebEngineHttpRequest &request) } // convert the custom headers into the format that chromium expects - QVector<QByteArray> headers = request.headers(); - for (QVector<QByteArray>::const_iterator it = headers.cbegin(); it != headers.cend(); ++it) { + QList<QByteArray> headers = request.headers(); + for (QList<QByteArray>::const_iterator it = headers.cbegin(); it != headers.cend(); ++it) { if (params.extra_headers.length() > 0) params.extra_headers += '\n'; params.extra_headers += (*it).toStdString() + ": " + request.header(*it).toStdString(); @@ -751,8 +752,7 @@ void WebContentsAdapter::setContent(const QByteArray &data, const QString &mimeT CHECK_VALID_RENDER_WIDGET_HOST_VIEW(m_webContents->GetRenderViewHost()); - WebEngineSettings *settings = m_adapterClient->webEngineSettings(); - settings->doApply(); + WebEngineSettings::get(m_adapterClient->webEngineSettings())->doApply(); QByteArray encodedData = data.toPercentEncoding(); std::string urlString; @@ -1116,7 +1116,6 @@ void WebContentsAdapter::download(const QUrl &url, const QString &suggestedFileN if (!dlm) return; - dlmd->markNextDownloadAsUserRequested(); dlm->SetDelegate(dlmd); net::NetworkTrafficAnnotationTag traffic_annotation = @@ -1641,19 +1640,19 @@ void WebContentsAdapter::enterDrag(QDragEnterEvent *e, const QPointF &screenPos) content::RenderViewHost *rvh = m_webContents->GetRenderViewHost(); rvh->GetWidget()->FilterDropData(m_currentDropData.get()); - rvh->GetWidget()->DragTargetDragEnter(*m_currentDropData, toGfx(e->posF()), toGfx(screenPos), + rvh->GetWidget()->DragTargetDragEnter(*m_currentDropData, toGfx(e->position()), toGfx(screenPos), toWeb(e->possibleActions()), - toWeb(e->mouseButtons()) | toWeb(e->keyboardModifiers())); + toWeb(e->buttons()) | toWeb(e->modifiers())); } Qt::DropAction WebContentsAdapter::updateDragPosition(QDragMoveEvent *e, const QPointF &screenPos) { CHECK_INITIALIZED(Qt::DropAction()); content::RenderViewHost *rvh = m_webContents->GetRenderViewHost(); - m_lastDragClientPos = e->posF(); + m_lastDragClientPos = e->position(); m_lastDragScreenPos = screenPos; rvh->GetWidget()->DragTargetDragOver(toGfx(m_lastDragClientPos), toGfx(m_lastDragScreenPos), toWeb(e->possibleActions()), - toWeb(e->mouseButtons()) | toWeb(e->keyboardModifiers())); + toWeb(e->buttons()) | toWeb(e->modifiers())); waitForUpdateDragActionCalled(); return toQt(blink::WebDragOperation(m_currentDropAction)); } @@ -1696,10 +1695,10 @@ void WebContentsAdapter::endDragging(QDropEvent *e, const QPointF &screenPos) CHECK_INITIALIZED(); content::RenderViewHost *rvh = m_webContents->GetRenderViewHost(); rvh->GetWidget()->FilterDropData(m_currentDropData.get()); - m_lastDragClientPos = e->posF(); + m_lastDragClientPos = e->position(); m_lastDragScreenPos = screenPos; rvh->GetWidget()->DragTargetDrop(*m_currentDropData, toGfx(m_lastDragClientPos), toGfx(m_lastDragScreenPos), - toWeb(e->mouseButtons()) | toWeb(e->keyboardModifiers())); + toWeb(e->buttons()) | toWeb(e->modifiers())); m_currentDropData.reset(); } @@ -1724,8 +1723,8 @@ void WebContentsAdapter::replaceMisspelling(const QString &word) void WebContentsAdapter::focusIfNecessary() { CHECK_INITIALIZED(); - const WebEngineSettings *settings = m_adapterClient->webEngineSettings(); - bool focusOnNavigation = settings->testAttribute(WebEngineSettings::FocusOnNavigationEnabled); + const QWebEngineSettings *settings = m_adapterClient->webEngineSettings(); + bool focusOnNavigation = settings->testAttribute(QWebEngineSettings::FocusOnNavigationEnabled); if (focusOnNavigation) m_webContents->Focus(); } diff --git a/src/core/web_contents_adapter.h b/src/core/web_contents_adapter.h index d833314f2..acf65f4d5 100644 --- a/src/core/web_contents_adapter.h +++ b/src/core/web_contents_adapter.h @@ -52,6 +52,7 @@ #define WEB_CONTENTS_ADAPTER_H #include "qtwebenginecoreglobal_p.h" +#include "qwebenginecontextmenurequest_p.h" #include "web_contents_adapter_client.h" #include <memory> #include <QtGui/qtgui-config.h> diff --git a/src/core/web_contents_adapter_client.h b/src/core/web_contents_adapter_client.h index 04df99f0e..ca5ca10de 100644 --- a/src/core/web_contents_adapter_client.h +++ b/src/core/web_contents_adapter_client.h @@ -57,13 +57,10 @@ #include <QFlags> #include <QRect> -#include <QSharedPointer> #include <QString> #include <QStringList> #include <QUrl> -QT_FORWARD_DECLARE_CLASS(CertificateErrorController) -QT_FORWARD_DECLARE_CLASS(ClientCertSelectController) QT_FORWARD_DECLARE_CLASS(QKeyEvent) QT_FORWARD_DECLARE_CLASS(QVariant) QT_FORWARD_DECLARE_CLASS(QWebEngineFindTextResult) @@ -71,6 +68,9 @@ QT_FORWARD_DECLARE_CLASS(QWebEngineQuotaRequest) QT_FORWARD_DECLARE_CLASS(QWebEngineRegisterProtocolHandlerRequest) QT_FORWARD_DECLARE_CLASS(QWebEngineUrlRequestInfo) QT_FORWARD_DECLARE_CLASS(QWebEngineUrlRequestInterceptor) +QT_FORWARD_DECLARE_CLASS(QWebEngineContextMenuRequest) +QT_FORWARD_DECLARE_CLASS(QWebEngineCertificateError); +QT_FORWARD_DECLARE_CLASS(QWebEngineSettings) namespace content { struct DropData; @@ -78,6 +78,8 @@ struct DropData; namespace QtWebEngineCore { +class CertificateErrorController; +class ClientCertSelectController; class AuthenticationDialogController; class ColorChooserController; class FilePickerController; @@ -91,279 +93,6 @@ class WebContentsAdapter; class WebContentsDelegateQt; class WebEngineSettings; -// Must match blink::WebReferrerPolicy -enum class ReferrerPolicy { - Always, - Default, - NoReferrerWhenDowngrade, - Never, - Origin, - OriginWhenCrossOrigin, - NoReferrerWhenDowngradeOriginWhenCrossOrigin, - SameOrigin, - StrictOrigin, - Last = StrictOrigin, -}; - -class WebEngineContextMenuSharedData : public QSharedData { - -public: - WebEngineContextMenuSharedData() - : hasImageContent(false) - , isEditable(false) - , isSpellCheckerEnabled(false) - , mediaType(0) - , mediaFlags(0) - , editFlags(0) - { - } - bool hasImageContent; - bool isEditable; - bool isSpellCheckerEnabled; - uint mediaType; - uint mediaFlags; - uint editFlags; - QPoint pos; - QUrl linkUrl; - QUrl unfilteredLinkUrl; - QUrl mediaUrl; - QString altText; - QString linkText; - QString titleText; - QString selectedText; - QString suggestedFileName; - QString misspelledWord; - QStringList spellCheckerSuggestions; - QUrl pageUrl; - QUrl frameUrl; - ReferrerPolicy referrerPolicy = ReferrerPolicy::Default; - // Some likely candidates for future additions as we add support for the related actions: - // bool isImageBlocked; - // <enum tbd> mediaType; - // ... -}; - -class WebEngineContextMenuData { -public: - // Must match blink::WebContextMenuData::MediaType: - enum MediaType { - // No special node is in context. - MediaTypeNone = 0x0, - // An image node is selected. - MediaTypeImage, - // A video node is selected. - MediaTypeVideo, - // An audio node is selected. - MediaTypeAudio, - // A canvas node is selected. - MediaTypeCanvas, - // A file node is selected. - MediaTypeFile, - // A plugin node is selected. - MediaTypePlugin, - MediaTypeLast = MediaTypePlugin - }; - // Must match blink::WebContextMenuData::MediaFlags: - enum MediaFlags { - MediaNone = 0x0, - MediaInError = 0x1, - MediaPaused = 0x2, - MediaMuted = 0x4, - MediaLoop = 0x8, - MediaCanSave = 0x10, - MediaHasAudio = 0x20, - MediaCanToggleControls = 0x40, - MediaControls = 0x80, - MediaCanPrint = 0x100, - MediaCanRotate = 0x200, - }; - - // Must match blink::WebContextMenuData::EditFlags: - enum EditFlags { - CanDoNone = 0x0, - CanUndo = 0x1, - CanRedo = 0x2, - CanCut = 0x4, - CanCopy = 0x8, - CanPaste = 0x10, - CanDelete = 0x20, - CanSelectAll = 0x40, - CanTranslate = 0x80, - CanEditRichly = 0x100, - }; - - WebEngineContextMenuData():d(new WebEngineContextMenuSharedData) { - } - - void setPosition(const QPoint &pos) { - d->pos = pos; - } - - QPoint position() const { - return d->pos; - } - - void setLinkUrl(const QUrl &url) { - d->linkUrl = url; - } - - QUrl linkUrl() const { - return d->linkUrl; - } - - void setUnfilteredLinkUrl(const QUrl &url) { - d->unfilteredLinkUrl = url; - } - - QUrl unfilteredLinkUrl() const { - return d->unfilteredLinkUrl; - } - - void setAltText(const QString &text) { - d->altText = text; - } - - QString altText() const { - return d->altText; - } - - void setLinkText(const QString &text) { - d->linkText = text; - } - - QString linkText() const { - return d->linkText; - } - - void setTitleText(const QString &text) { - d->titleText = text; - } - - QString titleText() const { - return d->titleText; - } - - void setSelectedText(const QString &text) { - d->selectedText = text; - } - - QString selectedText() const { - return d->selectedText; - } - - void setMediaUrl(const QUrl &url) { - d->mediaUrl = url; - } - - QUrl mediaUrl() const { - return d->mediaUrl; - } - - void setMediaType(MediaType type) { - d->mediaType = type; - } - - MediaType mediaType() const { - return MediaType(d->mediaType); - } - - void setHasImageContent(bool imageContent) { - d->hasImageContent = imageContent; - } - - bool hasImageContent() const { - return d->hasImageContent; - } - - void setMediaFlags(MediaFlags flags) { - d->mediaFlags = flags; - } - - MediaFlags mediaFlags() const { - return MediaFlags(d->mediaFlags); - } - - void setEditFlags(EditFlags flags) { - d->editFlags = flags; - } - - EditFlags editFlags() const { - return EditFlags(d->editFlags); - } - - void setSuggestedFileName(const QString &filename) { - d->suggestedFileName = filename; - } - - QString suggestedFileName() const { - return d->suggestedFileName; - } - - void setIsEditable(bool editable) { - d->isEditable = editable; - } - - bool isEditable() const { - return d->isEditable; - } - - void setIsSpellCheckerEnabled(bool spellCheckerEnabled) { - d->isSpellCheckerEnabled = spellCheckerEnabled; - } - - bool isSpellCheckerEnabled() const { - return d->isSpellCheckerEnabled; - } - - void setMisspelledWord(const QString &word) { - d->misspelledWord = word; - } - - QString misspelledWord() const { - return d->misspelledWord; - } - - void setSpellCheckerSuggestions(const QStringList &suggestions) { - d->spellCheckerSuggestions = suggestions; - } - - QStringList spellCheckerSuggestions() const { - return d->spellCheckerSuggestions; - } - - void setFrameUrl(const QUrl &url) { - d->frameUrl = url; - } - - QUrl frameUrl() const { - return d->frameUrl; - } - - void setPageUrl(const QUrl &url) { - d->pageUrl = url; - } - - QUrl pageUrl() const { - return d->pageUrl; - } - - QUrl referrerUrl() const { - return !d->frameUrl.isEmpty() ? d->frameUrl : d->pageUrl; - } - - void setReferrerPolicy(ReferrerPolicy referrerPolicy) { - d->referrerPolicy = referrerPolicy; - } - - ReferrerPolicy referrerPolicy() const { - return d->referrerPolicy; - } - -private: - QSharedDataPointer<WebEngineContextMenuSharedData> d; -}; - - class Q_WEBENGINECORE_PRIVATE_EXPORT WebContentsAdapterClient { public: // This must match window_open_disposition_list.h. @@ -465,7 +194,7 @@ public: virtual QColor backgroundColor() const = 0; virtual void loadStarted(const QUrl &provisionalUrl, bool isErrorPage = false) = 0; virtual void loadCommitted() = 0; - virtual void loadVisuallyCommitted() = 0; + virtual void didFirstVisuallyNonEmptyPaint() = 0; virtual void loadFinished(bool success, const QUrl &url, bool isErrorPage = false, int errorCode = 0, const QString &errorDescription = QString()) = 0; virtual void focusContainer() = 0; virtual void unhandledKeyEvent(QKeyEvent *event) = 0; @@ -476,7 +205,7 @@ public: virtual bool isBeingAdopted() = 0; virtual void close() = 0; virtual void windowCloseRejected() = 0; - virtual void contextMenuRequested(const WebEngineContextMenuData &) = 0; + virtual void contextMenuRequested(QWebEngineContextMenuRequest *request) = 0; virtual void navigationRequested(int navigationType, const QUrl &url, int &navigationRequestAction, bool isMainFrame) = 0; virtual void requestFullScreenMode(const QUrl &origin, bool fullscreen) = 0; virtual bool isFullScreenMode() const = 0; @@ -499,11 +228,11 @@ public: virtual void runMouseLockPermissionRequest(const QUrl &securityOrigin) = 0; virtual void runQuotaRequest(QWebEngineQuotaRequest) = 0; virtual void runRegisterProtocolHandlerRequest(QWebEngineRegisterProtocolHandlerRequest) = 0; - virtual WebEngineSettings *webEngineSettings() const = 0; + virtual QWebEngineSettings *webEngineSettings() const = 0; RenderProcessTerminationStatus renderProcessExitStatus(int); virtual void renderProcessTerminated(RenderProcessTerminationStatus terminationStatus, int exitCode) = 0; virtual void requestGeometryChange(const QRect &geometry, const QRect &frameGeometry) = 0; - virtual void allowCertificateError(const QSharedPointer<CertificateErrorController> &errorController) = 0; + virtual void allowCertificateError(const QWebEngineCertificateError &error) = 0; virtual void selectClientCert(const QSharedPointer<ClientCertSelectController> &selectController) = 0; virtual void updateScrollPosition(const QPointF &position) = 0; virtual void updateContentsSize(const QSizeF &size) = 0; diff --git a/src/core/web_contents_delegate_qt.cpp b/src/core/web_contents_delegate_qt.cpp index d5a3934fe..a6bd12ca8 100644 --- a/src/core/web_contents_delegate_qt.cpp +++ b/src/core/web_contents_delegate_qt.cpp @@ -60,7 +60,7 @@ #include "web_contents_view_qt.h" #include "web_engine_context.h" #include "web_engine_settings.h" - +#include "certificate_error_controller.h" #include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h" #include "components/error_page/common/error.h" #include "components/error_page/common/localized_error.h" @@ -234,7 +234,7 @@ QUrl WebContentsDelegateQt::url(content::WebContents* source) const { } void WebContentsDelegateQt::AddNewContents(content::WebContents* source, std::unique_ptr<content::WebContents> new_contents, WindowOpenDisposition disposition, const gfx::Rect& initial_pos, bool user_gesture, bool* was_blocked) { - Q_UNUSED(source) + Q_UNUSED(source); QSharedPointer<WebContentsAdapter> newAdapter = createWindow(std::move(new_contents), disposition, initial_pos, user_gesture); // Chromium can forget to pass user-agent override settings to new windows (see QTBUG-61774 and QTBUG-76249), // so set it here. Note the actual value doesn't really matter here. Only the second value does, but we try @@ -342,6 +342,10 @@ void WebContentsDelegateQt::EmitLoadStarted(const QUrl &url, bool isErrorPage) { if (m_lastLoadProgress >= 0 && m_lastLoadProgress < 100) // already running return; + for (auto &&wc : m_certificateErrorControllers) + if (auto controller = wc.lock()) + controller->deactivate(); + m_certificateErrorControllers.clear(); m_viewClient->loadStarted(url, isErrorPage); m_viewClient->updateNavigationActions(); m_viewClient->loadProgressChanged(0); @@ -601,7 +605,7 @@ void WebContentsDelegateQt::RunFileChooser(content::RenderFrameHost * /*frameHos bool WebContentsDelegateQt::DidAddMessageToConsole(content::WebContents *source, blink::mojom::ConsoleMessageLevel log_level, const base::string16 &message, int32_t line_no, const base::string16 &source_id) { - Q_UNUSED(source) + Q_UNUSED(source); m_viewClient->javaScriptConsoleMessage(mapToJavascriptConsoleMessageLevel(log_level), toQt(message), static_cast<int>(line_no), toQt(source_id)); return false; } @@ -632,7 +636,7 @@ void WebContentsDelegateQt::SetContentsBounds(content::WebContents *source, cons void WebContentsDelegateQt::UpdateTargetURL(content::WebContents* source, const GURL& url) { - Q_UNUSED(source) + Q_UNUSED(source); m_viewClient->didUpdateTargetURL(toQt(url)); } @@ -653,8 +657,8 @@ void WebContentsDelegateQt::DidFirstVisuallyNonEmptyPaint() void WebContentsDelegateQt::ActivateContents(content::WebContents* contents) { - WebEngineSettings *settings = m_viewClient->webEngineSettings(); - if (settings->testAttribute(settings->Attribute::AllowWindowActivationFromJavaScript)) + QWebEngineSettings *settings = m_viewClient->webEngineSettings(); + if (settings->testAttribute(QWebEngineSettings::AllowWindowActivationFromJavaScript)) contents->Focus(); } @@ -670,7 +674,7 @@ void WebContentsDelegateQt::RequestToLockMouse(content::WebContents *web_content void WebContentsDelegateQt::overrideWebPreferences(content::WebContents *webContents, content::WebPreferences *webPreferences) { - m_viewClient->webEngineSettings()->overrideWebPreferences(webContents, webPreferences); + WebEngineSettings::get(m_viewClient->webEngineSettings())->overrideWebPreferences(webContents, webPreferences); } QSharedPointer<WebContentsAdapter> @@ -686,9 +690,15 @@ WebContentsDelegateQt::createWindow(std::unique_ptr<content::WebContents> new_co toQt(initial_pos), m_initialTargetUrl); } -void WebContentsDelegateQt::allowCertificateError(const QSharedPointer<CertificateErrorController> &errorController) +void WebContentsDelegateQt::allowCertificateError( + const QSharedPointer<CertificateErrorController> &controller) { - m_viewClient->allowCertificateError(errorController); + QWebEngineCertificateError error(controller); + m_viewClient->allowCertificateError(error); + if (!error.isOverridable() || (!controller->deferred() && !controller->answered())) + error.rejectCertificate(); + else + m_certificateErrorControllers.append(controller); } void WebContentsDelegateQt::selectClientCert(const QSharedPointer<ClientCertSelectController> &selectController) @@ -705,17 +715,17 @@ extern WebContentsAdapterClient::NavigationType pageTransitionToNavigationType(u void WebContentsDelegateQt::launchExternalURL(const QUrl &url, ui::PageTransition page_transition, bool is_main_frame, bool has_user_gesture) { - WebEngineSettings *settings = m_viewClient->webEngineSettings(); + QWebEngineSettings *settings = m_viewClient->webEngineSettings(); bool navigationAllowedByPolicy = false; bool navigationRequestAccepted = true; switch (settings->unknownUrlSchemePolicy()) { - case WebEngineSettings::DisallowUnknownUrlSchemes: + case QWebEngineSettings::DisallowUnknownUrlSchemes: break; - case WebEngineSettings::AllowUnknownUrlSchemesFromUserInteraction: + case QWebEngineSettings::AllowUnknownUrlSchemesFromUserInteraction: navigationAllowedByPolicy = has_user_gesture; break; - case WebEngineSettings::AllowAllUnknownUrlSchemes: + case QWebEngineSettings::AllowAllUnknownUrlSchemes: navigationAllowedByPolicy = true; break; default: @@ -839,7 +849,7 @@ FindTextHelper *WebContentsDelegateQt::findTextHelper() } WebEngineSettings *WebContentsDelegateQt::webEngineSettings() const { - return m_viewClient->webEngineSettings(); + return WebEngineSettings::get(m_viewClient->webEngineSettings()); } WebContentsAdapter *WebContentsDelegateQt::webContentsAdapter() const diff --git a/src/core/web_contents_delegate_qt.h b/src/core/web_contents_delegate_qt.h index 159803840..4677a780a 100644 --- a/src/core/web_contents_delegate_qt.h +++ b/src/core/web_contents_delegate_qt.h @@ -52,11 +52,8 @@ #include "favicon_manager.h" #include "find_text_helper.h" #include "javascript_dialog_manager_qt.h" - -#include <QtCore/qvector.h> - -QT_FORWARD_DECLARE_CLASS(CertificateErrorController) -QT_FORWARD_DECLARE_CLASS(ClientCertSelectController) +#include <QtCore/qlist.h> +#include <QWebEngineCertificateError> namespace content { class ColorChooser; @@ -87,7 +84,7 @@ protected: private: WebContentsAdapterClient *m_viewClient; - QVector<content::FrameTreeNode *> m_observedNodes; + QList<content::FrameTreeNode *> m_observedNodes; }; class SavePageInfo @@ -216,7 +213,7 @@ private: int &streamCount(blink::mojom::MediaStreamType type); WebContentsAdapterClient *m_viewClient; - QVector<int64_t> m_loadingErrorFrameList; + QList<int64_t> m_loadingErrorFrameList; QScopedPointer<FaviconManager> m_faviconManager; QScopedPointer<FindTextHelper> m_findTextHelper; SavePageInfo m_savePageInfo; @@ -235,6 +232,7 @@ private: mutable bool m_pendingUrlUpdate = false; base::WeakPtrFactory<WebContentsDelegateQt> m_weakPtrFactory { this }; + QList<QWeakPointer<CertificateErrorController>> m_certificateErrorControllers; }; } // namespace QtWebEngineCore diff --git a/src/core/web_contents_view_qt.cpp b/src/core/web_contents_view_qt.cpp index 4e20c86ea..41f1c601e 100644 --- a/src/core/web_contents_view_qt.cpp +++ b/src/core/web_contents_view_qt.cpp @@ -73,7 +73,7 @@ void WebContentsViewQt::setFactoryClient(WebContentsAdapterClient* 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)); + view->setDelegate(m_factoryClient->CreateRenderWidgetHostViewQtDelegate(view->delegateClient())); } } @@ -94,7 +94,7 @@ content::RenderWidgetHostViewBase* WebContentsViewQt::CreateViewForWidget(conten RenderWidgetHostViewQt *view = new RenderWidgetHostViewQt(render_widget_host); if (m_factoryClient) { - view->setDelegate(m_factoryClient->CreateRenderWidgetHostViewQtDelegate(view)); + view->setDelegate(m_factoryClient->CreateRenderWidgetHostViewQtDelegate(view->delegateClient())); if (m_client) view->setAdapterClient(m_client); } @@ -107,7 +107,7 @@ content::RenderWidgetHostViewBase* WebContentsViewQt::CreateViewForChildWidget(c RenderWidgetHostViewQt *view = new RenderWidgetHostViewQt(render_widget_host); Q_ASSERT(m_client); - view->setDelegate(m_client->CreateRenderWidgetHostViewQtDelegateForPopup(view)); + view->setDelegate(m_client->CreateRenderWidgetHostViewQtDelegateForPopup(view->delegateClient())); view->setAdapterClient(m_client); return view; @@ -159,73 +159,85 @@ void WebContentsViewQt::FocusThroughTabTraversal(bool reverse) web_contents->GetRenderViewHost()->SetInitialFocus(reverse); } - -ASSERT_ENUMS_MATCH(WebEngineContextMenuData::MediaTypeNone, blink::ContextMenuDataMediaType::kNone) -ASSERT_ENUMS_MATCH(WebEngineContextMenuData::MediaTypeImage, blink::ContextMenuDataMediaType::kImage) -ASSERT_ENUMS_MATCH(WebEngineContextMenuData::MediaTypeVideo, blink::ContextMenuDataMediaType::kVideo) -ASSERT_ENUMS_MATCH(WebEngineContextMenuData::MediaTypeAudio, blink::ContextMenuDataMediaType::kAudio) -ASSERT_ENUMS_MATCH(WebEngineContextMenuData::MediaTypeCanvas, blink::ContextMenuDataMediaType::kCanvas) -ASSERT_ENUMS_MATCH(WebEngineContextMenuData::MediaTypeFile, blink::ContextMenuDataMediaType::kFile) -ASSERT_ENUMS_MATCH(WebEngineContextMenuData::MediaTypePlugin, blink::ContextMenuDataMediaType::kPlugin) - -ASSERT_ENUMS_MATCH(WebEngineContextMenuData::MediaNone, blink::WebContextMenuData::kMediaNone) -ASSERT_ENUMS_MATCH(WebEngineContextMenuData::MediaInError, blink::WebContextMenuData::kMediaInError) -ASSERT_ENUMS_MATCH(WebEngineContextMenuData::MediaPaused, blink::WebContextMenuData::kMediaPaused) -ASSERT_ENUMS_MATCH(WebEngineContextMenuData::MediaMuted, blink::WebContextMenuData::kMediaMuted) -ASSERT_ENUMS_MATCH(WebEngineContextMenuData::MediaLoop, blink::WebContextMenuData::kMediaLoop) -ASSERT_ENUMS_MATCH(WebEngineContextMenuData::MediaCanSave, blink::WebContextMenuData::kMediaCanSave) -ASSERT_ENUMS_MATCH(WebEngineContextMenuData::MediaHasAudio, blink::WebContextMenuData::kMediaHasAudio) -ASSERT_ENUMS_MATCH(WebEngineContextMenuData::MediaCanToggleControls, blink::WebContextMenuData::kMediaCanToggleControls) -ASSERT_ENUMS_MATCH(WebEngineContextMenuData::MediaControls, blink::WebContextMenuData::kMediaControls) -ASSERT_ENUMS_MATCH(WebEngineContextMenuData::MediaCanPrint, blink::WebContextMenuData::kMediaCanPrint) -ASSERT_ENUMS_MATCH(WebEngineContextMenuData::MediaCanRotate, blink::WebContextMenuData::kMediaCanRotate) - -ASSERT_ENUMS_MATCH(WebEngineContextMenuData::CanDoNone, blink::kCanDoNone) -ASSERT_ENUMS_MATCH(WebEngineContextMenuData::CanUndo, blink::kCanUndo) -ASSERT_ENUMS_MATCH(WebEngineContextMenuData::CanRedo, blink::kCanRedo) -ASSERT_ENUMS_MATCH(WebEngineContextMenuData::CanCut, blink::kCanCut) -ASSERT_ENUMS_MATCH(WebEngineContextMenuData::CanCopy, blink::kCanCopy) -ASSERT_ENUMS_MATCH(WebEngineContextMenuData::CanPaste, blink::kCanPaste) -ASSERT_ENUMS_MATCH(WebEngineContextMenuData::CanDelete, blink::kCanDelete) -ASSERT_ENUMS_MATCH(WebEngineContextMenuData::CanSelectAll, blink::kCanSelectAll) -ASSERT_ENUMS_MATCH(WebEngineContextMenuData::CanTranslate, blink::kCanTranslate) -ASSERT_ENUMS_MATCH(WebEngineContextMenuData::CanEditRichly, blink::kCanEditRichly) - -static inline WebEngineContextMenuData fromParams(const content::ContextMenuParams ¶ms) +ASSERT_ENUMS_MATCH(QWebEngineContextMenuRequest::MediaTypeNone, + blink::ContextMenuDataMediaType::kNone) +ASSERT_ENUMS_MATCH(QWebEngineContextMenuRequest::MediaTypeImage, + blink::ContextMenuDataMediaType::kImage) +ASSERT_ENUMS_MATCH(QWebEngineContextMenuRequest::MediaTypeVideo, + blink::ContextMenuDataMediaType::kVideo) +ASSERT_ENUMS_MATCH(QWebEngineContextMenuRequest::MediaTypeAudio, + blink::ContextMenuDataMediaType::kAudio) +ASSERT_ENUMS_MATCH(QWebEngineContextMenuRequest::MediaTypeCanvas, + blink::ContextMenuDataMediaType::kCanvas) +ASSERT_ENUMS_MATCH(QWebEngineContextMenuRequest::MediaTypeFile, + blink::ContextMenuDataMediaType::kFile) +ASSERT_ENUMS_MATCH(QWebEngineContextMenuRequest::MediaTypePlugin, + blink::ContextMenuDataMediaType::kPlugin) + +ASSERT_ENUMS_MATCH(QWebEngineContextMenuRequest::MediaInError, + blink::WebContextMenuData::kMediaInError) +ASSERT_ENUMS_MATCH(QWebEngineContextMenuRequest::MediaPaused, + blink::WebContextMenuData::kMediaPaused) +ASSERT_ENUMS_MATCH(QWebEngineContextMenuRequest::MediaMuted, blink::WebContextMenuData::kMediaMuted) +ASSERT_ENUMS_MATCH(QWebEngineContextMenuRequest::MediaLoop, blink::WebContextMenuData::kMediaLoop) +ASSERT_ENUMS_MATCH(QWebEngineContextMenuRequest::MediaCanSave, + blink::WebContextMenuData::kMediaCanSave) +ASSERT_ENUMS_MATCH(QWebEngineContextMenuRequest::MediaHasAudio, + blink::WebContextMenuData::kMediaHasAudio) +ASSERT_ENUMS_MATCH(QWebEngineContextMenuRequest::MediaCanToggleControls, + blink::WebContextMenuData::kMediaCanToggleControls) +ASSERT_ENUMS_MATCH(QWebEngineContextMenuRequest::MediaControls, + blink::WebContextMenuData::kMediaControls) +ASSERT_ENUMS_MATCH(QWebEngineContextMenuRequest::MediaCanPrint, + blink::WebContextMenuData::kMediaCanPrint) +ASSERT_ENUMS_MATCH(QWebEngineContextMenuRequest::MediaCanRotate, + blink::WebContextMenuData::kMediaCanRotate) + +ASSERT_ENUMS_MATCH(QWebEngineContextMenuRequest::CanUndo, blink::kCanUndo) +ASSERT_ENUMS_MATCH(QWebEngineContextMenuRequest::CanRedo, blink::kCanRedo) +ASSERT_ENUMS_MATCH(QWebEngineContextMenuRequest::CanCut, blink::kCanCut) +ASSERT_ENUMS_MATCH(QWebEngineContextMenuRequest::CanCopy, blink::kCanCopy) +ASSERT_ENUMS_MATCH(QWebEngineContextMenuRequest::CanPaste, blink::kCanPaste) +ASSERT_ENUMS_MATCH(QWebEngineContextMenuRequest::CanDelete, blink::kCanDelete) +ASSERT_ENUMS_MATCH(QWebEngineContextMenuRequest::CanSelectAll, blink::kCanSelectAll) +ASSERT_ENUMS_MATCH(QWebEngineContextMenuRequest::CanTranslate, blink::kCanTranslate) +ASSERT_ENUMS_MATCH(QWebEngineContextMenuRequest::CanEditRichly, blink::kCanEditRichly) + + +WebContentsViewQt::WebContentsViewQt(content::WebContents* webContents) +: m_webContents(webContents) + , m_client(nullptr) + , m_factoryClient(nullptr) + , m_contextMenuRequest( + new QWebEngineContextMenuRequest(new QWebEngineContextMenuRequestPrivate())) +{ } + + +void WebContentsViewQt::update(QWebEngineContextMenuRequest *request, + const content::ContextMenuParams ¶ms, bool spellcheckEnabled) { - WebEngineContextMenuData ret; - ret.setPosition(QPoint(params.x, params.y)); - ret.setLinkUrl(toQt(params.link_url)); - ret.setLinkText(toQt(params.link_text.data())); - ret.setAltText(toQt(params.alt_text.data())); - ret.setTitleText(toQt(params.title_text.data())); - ret.setUnfilteredLinkUrl(toQt(params.unfiltered_link_url)); - ret.setSelectedText(toQt(params.selection_text.data())); - ret.setMediaUrl(toQt(params.src_url)); - ret.setMediaType((WebEngineContextMenuData::MediaType)params.media_type); - ret.setHasImageContent(params.has_image_contents); - ret.setMediaFlags((WebEngineContextMenuData::MediaFlags)params.media_flags); - ret.setEditFlags((WebEngineContextMenuData::EditFlags)params.edit_flags); - ret.setSuggestedFileName(toQt(params.suggested_filename.data())); - ret.setIsEditable(params.is_editable); + auto *re = request->d.data(); + re->m_position = QPoint(params.x, params.y); + re->m_filteredLinkUrl = toQt(params.link_url); + re->m_linkText = toQt(params.link_text.data()); + re->m_altText = toQt(params.alt_text.data()); + re->m_titleText = toQt(params.title_text.data()); + re->m_unfilteredLinkUrl = toQt(params.unfiltered_link_url); + re->m_selectedText = toQt(params.selection_text.data()); + re->m_mediaUrl = toQt(params.src_url); + re->m_mediaType = (QWebEngineContextMenuRequest::MediaType)params.media_type; + re->m_hasImageContent = params.has_image_contents; + re->m_mediaFlags = (QWebEngineContextMenuRequest::MediaFlags)params.media_flags; + re->m_editFlags = (QWebEngineContextMenuRequest::EditFlags)params.edit_flags; + re->m_suggestedFileName = toQt(params.suggested_filename.data()); + re->m_isEditable = params.is_editable; #if QT_CONFIG(webengine_spellchecker) - ret.setMisspelledWord(toQt(params.misspelled_word)); - ret.setSpellCheckerSuggestions(fromVector(params.dictionary_suggestions)); + re->m_misspelledWord = toQt(params.misspelled_word); + re->m_spellCheckerSuggestions = fromVector(params.dictionary_suggestions); #endif - ret.setFrameUrl(toQt(params.frame_url)); - ret.setPageUrl(toQt(params.page_url)); - ret.setReferrerPolicy((ReferrerPolicy)params.referrer_policy); - return ret; -} - -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)); + re->m_frameUrl = toQt(params.frame_url); + re->m_pageUrl = toQt(params.page_url); + re->m_referrerPolicy = (ReferrerPolicy)params.referrer_policy; #if QT_CONFIG(webengine_spellchecker) // Do not use params.spellcheck_enabled, since it is never // correctly initialized for chrome asynchronous spellchecking. @@ -234,9 +246,21 @@ void WebContentsViewQt::ShowContextMenu(content::RenderFrameHost *, const conten // must be initialized to true due to the way how the initialization sequence // in SpellCheck works ie. typing the first word triggers the creation // of the SpellcheckService. Use user preference store instead. - contextMenuData.setIsSpellCheckerEnabled(m_client->profileAdapter()->isSpellCheckEnabled()); + re->m_isSpellCheckerEnabled = spellcheckEnabled; #endif - m_client->contextMenuRequested(contextMenuData); +} + +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; + } + const bool spellcheckEnabled = m_client->profileAdapter()->isSpellCheckEnabled(); + update(m_contextMenuRequest.get(), params, spellcheckEnabled); + m_client->contextMenuRequested(m_contextMenuRequest.get()); } Qt::DropActions toQtDropActions(blink::WebDragOperationsMask ops) diff --git a/src/core/web_contents_view_qt.h b/src/core/web_contents_view_qt.h index 3c89bf3b0..acf4a1eba 100644 --- a/src/core/web_contents_view_qt.h +++ b/src/core/web_contents_view_qt.h @@ -45,6 +45,8 @@ #include "api/qtwebenginecoreglobal_p.h" +QT_FORWARD_DECLARE_CLASS(QWebEngineContextMenuRequest) + namespace content { class WebContents; } @@ -59,12 +61,7 @@ class WebContentsViewQt public: static inline WebContentsViewQt *from(WebContentsView *view) { return static_cast<WebContentsViewQt*>(view); } - WebContentsViewQt(content::WebContents* webContents) - : m_webContents(webContents) - , m_client(nullptr) - , m_factoryClient(nullptr) - { } - + WebContentsViewQt(content::WebContents* webContents); void setFactoryClient(WebContentsAdapterClient* client); void setClient(WebContentsAdapterClient* client); WebContentsAdapterClient *client() { return m_client; } @@ -127,9 +124,14 @@ public: void TakeFocus(bool reverse) override; private: + static void update(QWebEngineContextMenuRequest *request, + const content::ContextMenuParams ¶ms, bool spellcheckEnabled); + +private: content::WebContents *m_webContents; WebContentsAdapterClient *m_client; WebContentsAdapterClient *m_factoryClient; + std::unique_ptr<QWebEngineContextMenuRequest> m_contextMenuRequest; }; } // namespace QtWebEngineCore diff --git a/src/core/web_engine_context.cpp b/src/core/web_engine_context.cpp index 6d76a818d..32701f230 100644 --- a/src/core/web_engine_context.cpp +++ b/src/core/web_engine_context.cpp @@ -130,16 +130,15 @@ #include <QOffscreenSurface> #if QT_CONFIG(opengl) # include <QOpenGLContext> +# include <qopenglcontext_platform.h> #endif #include <QQuickWindow> #include <QStringList> #include <QSurfaceFormat> -#include <QVector> #include <QNetworkProxy> #include <QtGui/qpa/qplatformintegration.h> #include <QtGui/private/qguiapplication_p.h> - -using namespace QtWebEngineCore; +#include <QLoggingCategory> #if QT_CONFIG(opengl) QT_BEGIN_NAMESPACE @@ -147,10 +146,10 @@ Q_GUI_EXPORT QOpenGLContext *qt_gl_global_share_context(); QT_END_NAMESPACE #endif -namespace { +namespace QtWebEngineCore { #if QT_CONFIG(opengl) -bool usingANGLE() +static bool usingANGLE() { #if defined(Q_OS_WIN) if (qt_gl_global_share_context()) @@ -161,7 +160,7 @@ bool usingANGLE() #endif } -bool usingDefaultSGBackend() +static bool usingDefaultSGBackend() { const QStringList args = QGuiApplication::arguments(); @@ -182,16 +181,105 @@ bool usingDefaultSGBackend() return device.isEmpty(); } + +bool usingSoftwareDynamicGL() +{ + if (QCoreApplication::testAttribute(Qt::AA_UseSoftwareOpenGL)) + return true; +#if defined(Q_OS_WIN) + HMODULE handle = QPlatformInterface::QWGLContext::openGLModuleHandle(); + wchar_t path[MAX_PATH]; + DWORD size = GetModuleFileName(handle, path, MAX_PATH); + QFileInfo openGLModule(QString::fromWCharArray(path, size)); + return openGLModule.fileName() == QLatin1String("opengl32sw.dll"); +#else + return false; +#endif +} + +static const char *getGLType(bool enableGLSoftwareRendering) +{ + const char *glType = nullptr; + 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()) { + qWarning("WebEngineContext used before QtWebEngine::initialize() or OpenGL context " + "creation failed."); + } else { + const QSurfaceFormat sharedFormat = qt_gl_global_share_context()->format(); + switch (sharedFormat.renderableType()) { + case QSurfaceFormat::OpenGL: + glType = gl::kGLImplementationDesktopName; + // Check if Core profile was requested and is supported. + if (sharedFormat.profile() == QSurfaceFormat::CoreProfile) { +#ifdef Q_OS_MACOS + glType = gl::kGLImplementationCoreProfileName; +#else + qWarning("An OpenGL Core Profile was requested, but it is not supported " + "on the current platform. Falling back to a non-Core profile. " + "Note that this might cause rendering issues."); +#endif + } + break; + case QSurfaceFormat::OpenGLES: + glType = usingANGLE() ? gl::kGLImplementationANGLEName + : gl::kGLImplementationEGLName; + break; + case QSurfaceFormat::OpenVG: + case QSurfaceFormat::DefaultRenderableType: + default: + // Shared contex created but no rederable type set. + qWarning("Unsupported rendering surface format. Please open bug report at " + "https://bugreports.qt.io"); + } + } + } + return glType; +} +#else +static cont char *getGLType(bool enableGLSoftwareRendering) +{ + return nullptr; +} #endif // QT_CONFIG(opengl) + #if QT_CONFIG(webengine_pepper_plugins) void dummyGetPluginCallback(const std::vector<content::WebPluginInfo>&) { } #endif -} // namespace - -namespace QtWebEngineCore { +static void logContext(const char *glType, base::CommandLine *cmd) +{ + QLoggingCategory webEngineContextLog("qt.webenginecontext"); + if (webEngineContextLog.isInfoEnabled()) { + const QSurfaceFormat sharedFormat = qt_gl_global_share_context()->format(); + const auto profile = QMetaEnum::fromType<QSurfaceFormat::OpenGLContextProfile>().valueToKey( + sharedFormat.profile()); + const auto type = QMetaEnum::fromType<QSurfaceFormat::RenderableType>().valueToKey( + sharedFormat.renderableType()); + const base::CommandLine::SwitchMap switch_map = cmd->GetSwitches(); + QStringList params; + for (const auto &pair : switch_map) + params << " * " << toQt(pair.first) + << toQt(pair.second) << "\n"; + qCInfo(webEngineContextLog, + "\n\nGLImplementation: %s\n" + "Surface Type: %s\n" + "Surface Profile: %s\n" + "Surface Version: %d.%d\n" + "Using Default SG Backend: %s\n" + "Using Software Dynamic GL: %s\n" + "Using Angle: %s\n\n" + "Init Parameters:\n %s", + glType, type, profile, sharedFormat.majorVersion(), sharedFormat.minorVersion(), + usingDefaultSGBackend() ? "yes" : "no", usingSoftwareDynamicGL() ? "yes" : "no", + usingANGLE() ? "yes" : "no", qPrintable(params.join(" "))); + } +} #if defined(Q_OS_WIN) sandbox::SandboxInterfaceInfo *staticSandboxInterfaceInfo(sandbox::SandboxInterfaceInfo *info) @@ -207,36 +295,22 @@ sandbox::SandboxInterfaceInfo *staticSandboxInterfaceInfo(sandbox::SandboxInterf extern std::unique_ptr<base::MessagePump> messagePumpFactory(); -bool usingSoftwareDynamicGL() +static void setupProxyPac(base::CommandLine *commandLine) { - if (QCoreApplication::testAttribute(Qt::AA_UseSoftwareOpenGL)) - return true; -#if defined(Q_OS_WIN) && QT_CONFIG(opengl) - HMODULE handle = static_cast<HMODULE>(QOpenGLContext::openGLModuleHandle()); - wchar_t path[MAX_PATH]; - DWORD size = GetModuleFileName(handle, path, MAX_PATH); - QFileInfo openGLModule(QString::fromWCharArray(path, size)); - return openGLModule.fileName() == QLatin1String("opengl32sw.dll"); -#else - return false; -#endif -} - -void setupProxyPac(base::CommandLine *commandLine){ if (commandLine->HasSwitch(switches::kProxyPacUrl)) { QUrl pac_url(toQt(commandLine->GetSwitchValueASCII(switches::kProxyPacUrl))); if (pac_url.isValid() && (pac_url.isLocalFile() || - !pac_url.scheme().compare(QLatin1String("qrc"), Qt::CaseInsensitive))) { + !pac_url.scheme().compare(QLatin1String("qrc"), Qt::CaseInsensitive))) { QFile file; if (pac_url.isLocalFile()) - file.setFileName(pac_url.toLocalFile()); + file.setFileName(pac_url.toLocalFile()); else - file.setFileName(pac_url.path().prepend(QChar(':'))); + file.setFileName(pac_url.path().prepend(QChar(':'))); if (file.exists() && file.open(QIODevice::ReadOnly | QIODevice::Text)) { - QByteArray ba = file.readAll(); - commandLine->RemoveSwitch(switches::kProxyPacUrl); - commandLine->AppendSwitchASCII(switches::kProxyPacUrl, - ba.toBase64().prepend("data:application/x-javascript-config;base64,").toStdString()); + QByteArray ba = file.readAll(); + commandLine->RemoveSwitch(switches::kProxyPacUrl); + commandLine->AppendSwitchASCII(switches::kProxyPacUrl, + ba.toBase64().prepend("data:application/x-javascript-config;base64,").toStdString()); } } } @@ -563,12 +637,6 @@ WebEngineContext::WebEngineContext() QStringList appArgs = QCoreApplication::arguments(); - // 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.contains(QStringLiteral("--disable-embedded-switches")); @@ -595,30 +663,6 @@ WebEngineContext::WebEngineContext() parsedCommandLine->AppendSwitch(switches::kEnableThreadedCompositing); -#if defined(Q_OS_WIN) - // This switch is used in Chromium's gl_context_wgl.cc file to determine whether to create - // 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. 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 - // Do not advertise a feature we have removed at compile time parsedCommandLine->AppendSwitch(switches::kDisableSpeechAPI); @@ -674,74 +718,12 @@ WebEngineContext::WebEngineContext() GLContextHelper::initialize(); - const char *glType = 0; -#if QT_CONFIG(opengl) - - 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. - // 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") - || usingANGLE()) - { - if (qt_gl_global_share_context()->isOpenGLES()) { - glType = usingANGLE() ? gl::kGLImplementationANGLEName : gl::kGLImplementationEGLName; - } else { - QOpenGLContext context; - QSurfaceFormat format; - - format.setRenderableType(QSurfaceFormat::OpenGL); - format.setVersion(2, 0); - - context.setFormat(format); - context.setShareContext(qt_gl_global_share_context()); - if (context.create()) { - QOffscreenSurface surface; - - surface.setFormat(format); - surface.create(); - - if (context.makeCurrent(&surface)) { - if (context.hasExtension("GL_ARB_ES2_compatibility")) - glType = gl::kGLImplementationEGLName; - - context.doneCurrent(); - } - - surface.destroy(); - } - } - } else { - if (!qt_gl_global_share_context()->isOpenGLES()) { - // Default to Desktop non-Core profile OpenGL. - glType = gl::kGLImplementationDesktopName; - - // Check if Core profile was requested and is supported. - QSurfaceFormat globalSharedFormat = qt_gl_global_share_context()->format(); - if (globalSharedFormat.profile() == QSurfaceFormat::CoreProfile) { -#ifdef Q_OS_MACOS - glType = gl::kGLImplementationCoreProfileName; -#else - qWarning("An OpenGL Core Profile was requested, but it is not supported " - "on the current platform. Falling back to a non-Core profile. " - "Note that this might cause rendering issues."); -#endif - } - } - } - if (qt_gl_global_share_context()->format().profile() == QSurfaceFormat::CompatibilityProfile) - parsedCommandLine->AppendSwitch(switches::kCreateDefaultGLContext); - } else { - qWarning("WebEngineContext used before QtWebEngine::initialize() or OpenGL context creation failed."); - } - } -#endif // QT_CONFIG(opengl) + // 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 + const bool enableGLSoftwareRendering = appArgs.contains(QStringLiteral("--enable-webgl-software-rendering")); + const char *glType = getGLType(enableGLSoftwareRendering); if (glType) { parsedCommandLine->AppendSwitchASCII(switches::kUseGL, glType); @@ -750,6 +732,29 @@ WebEngineContext::WebEngineContext() parsedCommandLine->AppendSwitch(switches::kDisableGpuRasterization); parsedCommandLine->AppendSwitch(switches::kIgnoreGpuBlacklist); } + const QSurfaceFormat sharedFormat = QOpenGLContext::globalShareContext()->format(); + if (sharedFormat.profile() == QSurfaceFormat::CompatibilityProfile) + parsedCommandLine->AppendSwitch(switches::kCreateDefaultGLContext); +#if defined(Q_OS_WIN) + // This switch is used in Chromium's gl_context_wgl.cc file to determine whether to create + // 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. 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 = QOpenGLContext::globalShareContext()->isOpenGLES() + && QOpenGLContext::globalShareContext()->format().majorVersion() == 2; + if (!usingANGLE() || isGLES2Context) + parsedCommandLine->AppendSwitch(switches::kDisableES3GLContext); +#endif } else { parsedCommandLine->AppendSwitch(switches::kDisableGpu); } @@ -832,6 +837,8 @@ WebEngineContext::WebEngineContext() #endif content::WebUIControllerFactory::RegisterFactory(WebUIControllerFactoryQt::GetInstance()); + + logContext(glType, parsedCommandLine); } #if QT_CONFIG(webengine_printing_and_pdf) @@ -850,8 +857,8 @@ gpu::SyncPointManager *WebEngineContext::syncPointManager() return spm; QMutexLocker lock(&s_spmMutex); if (!s_syncPointManager) - s_syncPointManager.store(new gpu::SyncPointManager()); - return s_syncPointManager.load(); + s_syncPointManager.storeRelaxed(new gpu::SyncPointManager()); + return s_syncPointManager.loadRelaxed(); } base::CommandLine* WebEngineContext::commandLine() { diff --git a/src/core/web_engine_context.h b/src/core/web_engine_context.h index e2190f8a2..fcc569969 100644 --- a/src/core/web_engine_context.h +++ b/src/core/web_engine_context.h @@ -47,7 +47,7 @@ #include "base/values.h" #include <QtGui/qtgui-config.h> -#include <QVector> +#include <QList> namespace base { class RunLoop; @@ -144,7 +144,7 @@ private: std::unique_ptr<QObject> m_globalQObject; std::unique_ptr<ProfileAdapter> m_defaultProfileAdapter; std::unique_ptr<DevToolsServerQt> m_devtoolsServer; - QVector<ProfileAdapter*> m_profileAdapters; + QList<ProfileAdapter*> m_profileAdapters; #if QT_CONFIG(accessibility) std::unique_ptr<AccessibilityActivationObserver> m_accessibilityActivationObserver; #endif diff --git a/src/core/web_engine_settings.cpp b/src/core/web_engine_settings.cpp index 957fe2b7d..693c6f6fb 100644 --- a/src/core/web_engine_settings.cpp +++ b/src/core/web_engine_settings.cpp @@ -59,13 +59,12 @@ #include <QFont> #include <QTimer> -#include <QTouchDevice> namespace QtWebEngineCore { -QHash<WebEngineSettings::Attribute, bool> WebEngineSettings::s_defaultAttributes; -QHash<WebEngineSettings::FontFamily, QString> WebEngineSettings::s_defaultFontFamilies; -QHash<WebEngineSettings::FontSize, int> WebEngineSettings::s_defaultFontSizes; +QHash<QWebEngineSettings::WebAttribute, bool> WebEngineSettings::s_defaultAttributes; +QHash<QWebEngineSettings::FontFamily, QString> WebEngineSettings::s_defaultFontFamilies; +QHash<QWebEngineSettings::FontSize, int> WebEngineSettings::s_defaultFontSizes; static const int batchTimerTimeout = 0; @@ -93,13 +92,14 @@ static inline bool isTouchEventsAPIEnabled() { } WebEngineSettings::WebEngineSettings(WebEngineSettings *_parentSettings) - : m_adapter(0) + : m_adapter(nullptr) , parentSettings(_parentSettings) - , m_unknownUrlSchemePolicy(WebEngineSettings::InheritedUnknownUrlSchemePolicy) + , m_unknownUrlSchemePolicy(QWebEngineSettings::InheritedUnknownUrlSchemePolicy) { if (parentSettings) parentSettings->childSettings.insert(this); - + else + initDefaults(); m_batchTimer.setSingleShot(true); m_batchTimer.setInterval(batchTimerTimeout); QObject::connect(&m_batchTimer, &QTimer::timeout, [this]() { @@ -132,13 +132,13 @@ void WebEngineSettings::overrideWebPreferences(content::WebContents *webContents } } -void WebEngineSettings::setAttribute(WebEngineSettings::Attribute attr, bool on) +void WebEngineSettings::setAttribute(QWebEngineSettings::WebAttribute attr, bool on) { m_attributes.insert(attr, on); scheduleApplyRecursively(); } -bool WebEngineSettings::testAttribute(WebEngineSettings::Attribute attr) const +bool WebEngineSettings::testAttribute(QWebEngineSettings::WebAttribute attr) const { auto it = m_attributes.constFind(attr); if (it != m_attributes.constEnd()) @@ -151,7 +151,7 @@ bool WebEngineSettings::testAttribute(WebEngineSettings::Attribute attr) const return s_defaultAttributes.value(attr); } -bool WebEngineSettings::isAttributeExplicitlySet(Attribute attr) const +bool WebEngineSettings::isAttributeExplicitlySet(QWebEngineSettings::WebAttribute attr) const { if (m_attributes.contains(attr)) return true; @@ -162,19 +162,19 @@ bool WebEngineSettings::isAttributeExplicitlySet(Attribute attr) const return false; } -void WebEngineSettings::resetAttribute(WebEngineSettings::Attribute attr) +void WebEngineSettings::resetAttribute(QWebEngineSettings::WebAttribute attr) { m_attributes.remove(attr); scheduleApplyRecursively(); } -void WebEngineSettings::setFontFamily(WebEngineSettings::FontFamily which, const QString &family) +void WebEngineSettings::setFontFamily(QWebEngineSettings::FontFamily which, const QString &family) { m_fontFamilies.insert(which, family); scheduleApplyRecursively(); } -QString WebEngineSettings::fontFamily(WebEngineSettings::FontFamily which) +QString WebEngineSettings::fontFamily(QWebEngineSettings::FontFamily which) { if (!parentSettings) { Q_ASSERT(s_defaultFontFamilies.contains(which)); @@ -183,19 +183,19 @@ QString WebEngineSettings::fontFamily(WebEngineSettings::FontFamily which) return m_fontFamilies.value(which, parentSettings->fontFamily(which)); } -void WebEngineSettings::resetFontFamily(WebEngineSettings::FontFamily which) +void WebEngineSettings::resetFontFamily(QWebEngineSettings::FontFamily which) { m_fontFamilies.remove(which); scheduleApplyRecursively(); } -void WebEngineSettings::setFontSize(WebEngineSettings::FontSize type, int size) +void WebEngineSettings::setFontSize(QWebEngineSettings::FontSize type, int size) { m_fontSizes.insert(type, size); scheduleApplyRecursively(); } -int WebEngineSettings::fontSize(WebEngineSettings::FontSize type) const +int WebEngineSettings::fontSize(QWebEngineSettings::FontSize type) const { if (!parentSettings) { Q_ASSERT(s_defaultFontSizes.contains(type)); @@ -204,7 +204,7 @@ int WebEngineSettings::fontSize(WebEngineSettings::FontSize type) const return m_fontSizes.value(type, parentSettings->fontSize(type)); } -void WebEngineSettings::resetFontSize(WebEngineSettings::FontSize type) +void WebEngineSettings::resetFontSize(QWebEngineSettings::FontSize type) { m_fontSizes.remove(type); scheduleApplyRecursively(); @@ -223,42 +223,42 @@ QString WebEngineSettings::defaultTextEncoding() const return m_defaultEncoding.isEmpty()? parentSettings->defaultTextEncoding() : m_defaultEncoding; } -void WebEngineSettings::setUnknownUrlSchemePolicy(WebEngineSettings::UnknownUrlSchemePolicy policy) +void WebEngineSettings::setUnknownUrlSchemePolicy(QWebEngineSettings::UnknownUrlSchemePolicy policy) { m_unknownUrlSchemePolicy = policy; } -WebEngineSettings::UnknownUrlSchemePolicy WebEngineSettings::unknownUrlSchemePolicy() const +QWebEngineSettings::UnknownUrlSchemePolicy WebEngineSettings::unknownUrlSchemePolicy() const { // value InheritedUnknownUrlSchemePolicy means it is taken from parent, if possible. If there // is no parent, then AllowUnknownUrlSchemesFromUserInteraction (the default behavior) is used. - if (m_unknownUrlSchemePolicy != InheritedUnknownUrlSchemePolicy) + if (m_unknownUrlSchemePolicy != QWebEngineSettings::InheritedUnknownUrlSchemePolicy) return m_unknownUrlSchemePolicy; if (parentSettings) return parentSettings->unknownUrlSchemePolicy(); - return AllowUnknownUrlSchemesFromUserInteraction; + return QWebEngineSettings::AllowUnknownUrlSchemesFromUserInteraction; } void WebEngineSettings::initDefaults() { if (s_defaultAttributes.isEmpty()) { // Initialize the default settings. - s_defaultAttributes.insert(AutoLoadImages, true); - s_defaultAttributes.insert(JavascriptEnabled, true); - s_defaultAttributes.insert(JavascriptCanOpenWindows, true); - s_defaultAttributes.insert(JavascriptCanAccessClipboard, false); - s_defaultAttributes.insert(LinksIncludedInFocusChain, true); - s_defaultAttributes.insert(LocalStorageEnabled, true); - s_defaultAttributes.insert(LocalContentCanAccessRemoteUrls, false); - s_defaultAttributes.insert(XSSAuditingEnabled, false); - s_defaultAttributes.insert(SpatialNavigationEnabled, false); - s_defaultAttributes.insert(LocalContentCanAccessFileUrls, true); - s_defaultAttributes.insert(HyperlinkAuditingEnabled, false); - s_defaultAttributes.insert(ErrorPageEnabled, true); - s_defaultAttributes.insert(PluginsEnabled, false); - s_defaultAttributes.insert(FullScreenSupportEnabled, false); - s_defaultAttributes.insert(ScreenCaptureEnabled, false); - s_defaultAttributes.insert(ShowScrollBars, true); + s_defaultAttributes.insert(QWebEngineSettings::AutoLoadImages, true); + s_defaultAttributes.insert(QWebEngineSettings::JavascriptEnabled, true); + s_defaultAttributes.insert(QWebEngineSettings::JavascriptCanOpenWindows, true); + s_defaultAttributes.insert(QWebEngineSettings::JavascriptCanAccessClipboard, false); + s_defaultAttributes.insert(QWebEngineSettings::LinksIncludedInFocusChain, true); + s_defaultAttributes.insert(QWebEngineSettings::LocalStorageEnabled, true); + s_defaultAttributes.insert(QWebEngineSettings::LocalContentCanAccessRemoteUrls, false); + s_defaultAttributes.insert(QWebEngineSettings::XSSAuditingEnabled, false); + s_defaultAttributes.insert(QWebEngineSettings::SpatialNavigationEnabled, false); + s_defaultAttributes.insert(QWebEngineSettings::LocalContentCanAccessFileUrls, true); + s_defaultAttributes.insert(QWebEngineSettings::HyperlinkAuditingEnabled, false); + s_defaultAttributes.insert(QWebEngineSettings::ErrorPageEnabled, true); + s_defaultAttributes.insert(QWebEngineSettings::PluginsEnabled, false); + s_defaultAttributes.insert(QWebEngineSettings::FullScreenSupportEnabled, false); + s_defaultAttributes.insert(QWebEngineSettings::ScreenCaptureEnabled, false); + s_defaultAttributes.insert(QWebEngineSettings::ShowScrollBars, true); // The following defaults matches logic in render_view_host_impl.cc // But first we must ensure the WebContext has been initialized QtWebEngineCore::WebEngineContext::current(); @@ -270,27 +270,30 @@ void WebEngineSettings::initDefaults() bool accelerated2dCanvas = !commandLine->HasSwitch(switches::kDisableAccelerated2dCanvas); bool allowRunningInsecureContent = commandLine->HasSwitch(switches::kAllowRunningInsecureContent); - s_defaultAttributes.insert(ScrollAnimatorEnabled, smoothScrolling); - s_defaultAttributes.insert(WebGLEnabled, webGL); - s_defaultAttributes.insert(Accelerated2dCanvasEnabled, accelerated2dCanvas); - s_defaultAttributes.insert(AutoLoadIconsForPage, true); - s_defaultAttributes.insert(TouchIconsEnabled, false); - s_defaultAttributes.insert(FocusOnNavigationEnabled, false); - s_defaultAttributes.insert(PrintElementBackgrounds, true); - s_defaultAttributes.insert(AllowRunningInsecureContent, allowRunningInsecureContent); - s_defaultAttributes.insert(AllowGeolocationOnInsecureOrigins, false); - s_defaultAttributes.insert(AllowWindowActivationFromJavaScript, false); + s_defaultAttributes.insert(QWebEngineSettings::ScrollAnimatorEnabled, smoothScrolling); + s_defaultAttributes.insert(QWebEngineSettings::WebGLEnabled, webGL); + s_defaultAttributes.insert(QWebEngineSettings::Accelerated2dCanvasEnabled, + accelerated2dCanvas); + s_defaultAttributes.insert(QWebEngineSettings::AutoLoadIconsForPage, true); + s_defaultAttributes.insert(QWebEngineSettings::TouchIconsEnabled, false); + s_defaultAttributes.insert(QWebEngineSettings::FocusOnNavigationEnabled, false); + s_defaultAttributes.insert(QWebEngineSettings::PrintElementBackgrounds, true); + s_defaultAttributes.insert(QWebEngineSettings::AllowRunningInsecureContent, + allowRunningInsecureContent); + s_defaultAttributes.insert(QWebEngineSettings::AllowGeolocationOnInsecureOrigins, false); + s_defaultAttributes.insert(QWebEngineSettings::AllowWindowActivationFromJavaScript, false); bool playbackRequiresUserGesture = false; if (commandLine->HasSwitch(switches::kAutoplayPolicy)) playbackRequiresUserGesture = (commandLine->GetSwitchValueASCII(switches::kAutoplayPolicy) != switches::autoplay::kNoUserGestureRequiredPolicy); - s_defaultAttributes.insert(PlaybackRequiresUserGesture, playbackRequiresUserGesture); - s_defaultAttributes.insert(WebRTCPublicInterfacesOnly, false); - s_defaultAttributes.insert(JavascriptCanPaste, false); - s_defaultAttributes.insert(DnsPrefetchEnabled, false); + s_defaultAttributes.insert(QWebEngineSettings::PlaybackRequiresUserGesture, + playbackRequiresUserGesture); + s_defaultAttributes.insert(QWebEngineSettings::WebRTCPublicInterfacesOnly, false); + s_defaultAttributes.insert(QWebEngineSettings::JavascriptCanPaste, false); + s_defaultAttributes.insert(QWebEngineSettings::DnsPrefetchEnabled, false); #if QT_CONFIG(webengine_extensions) - s_defaultAttributes.insert(PdfViewerEnabled, true); + s_defaultAttributes.insert(QWebEngineSettings::PdfViewerEnabled, true); #else - s_defaultAttributes.insert(PdfViewerEnabled, false); + s_defaultAttributes.insert(QWebEngineSettings::PdfViewerEnabled, false); #endif } @@ -298,32 +301,34 @@ void WebEngineSettings::initDefaults() // Default fonts QFont defaultFont; defaultFont.setStyleHint(QFont::Serif); - s_defaultFontFamilies.insert(StandardFont, defaultFont.defaultFamily()); - s_defaultFontFamilies.insert(SerifFont, defaultFont.defaultFamily()); - s_defaultFontFamilies.insert(PictographFont, defaultFont.defaultFamily()); + s_defaultFontFamilies.insert(QWebEngineSettings::StandardFont, defaultFont.defaultFamily()); + s_defaultFontFamilies.insert(QWebEngineSettings::SerifFont, defaultFont.defaultFamily()); + s_defaultFontFamilies.insert(QWebEngineSettings::PictographFont, + defaultFont.defaultFamily()); defaultFont.setStyleHint(QFont::Fantasy); - s_defaultFontFamilies.insert(FantasyFont, defaultFont.defaultFamily()); + s_defaultFontFamilies.insert(QWebEngineSettings::FantasyFont, defaultFont.defaultFamily()); defaultFont.setStyleHint(QFont::Cursive); - s_defaultFontFamilies.insert(CursiveFont, defaultFont.defaultFamily()); + s_defaultFontFamilies.insert(QWebEngineSettings::CursiveFont, defaultFont.defaultFamily()); defaultFont.setStyleHint(QFont::SansSerif); - s_defaultFontFamilies.insert(SansSerifFont, defaultFont.defaultFamily()); + s_defaultFontFamilies.insert(QWebEngineSettings::SansSerifFont, + defaultFont.defaultFamily()); defaultFont.setStyleHint(QFont::Monospace); - s_defaultFontFamilies.insert(FixedFont, defaultFont.defaultFamily()); + s_defaultFontFamilies.insert(QWebEngineSettings::FixedFont, defaultFont.defaultFamily()); } if (s_defaultFontSizes.isEmpty()) { - s_defaultFontSizes.insert(MinimumFontSize, 0); - s_defaultFontSizes.insert(MinimumLogicalFontSize, 6); - s_defaultFontSizes.insert(DefaultFixedFontSize, 13); - s_defaultFontSizes.insert(DefaultFontSize, 16); + s_defaultFontSizes.insert(QWebEngineSettings::MinimumFontSize, 0); + s_defaultFontSizes.insert(QWebEngineSettings::MinimumLogicalFontSize, 6); + s_defaultFontSizes.insert(QWebEngineSettings::DefaultFixedFontSize, 13); + s_defaultFontSizes.insert(QWebEngineSettings::DefaultFontSize, 16); } m_defaultEncoding = QStringLiteral("ISO-8859-1"); - m_unknownUrlSchemePolicy = InheritedUnknownUrlSchemePolicy; + m_unknownUrlSchemePolicy = QWebEngineSettings::InheritedUnknownUrlSchemePolicy; } void WebEngineSettings::scheduleApply() @@ -363,46 +368,59 @@ void WebEngineSettings::applySettingsToWebPreferences(content::WebPreferences *p } // Attributes mapping. - prefs->loads_images_automatically = testAttribute(AutoLoadImages); - prefs->javascript_enabled = testAttribute(JavascriptEnabled); - prefs->javascript_can_access_clipboard = testAttribute(JavascriptCanAccessClipboard); - prefs->tabs_to_links = testAttribute(LinksIncludedInFocusChain); - prefs->local_storage_enabled = testAttribute(LocalStorageEnabled); - prefs->databases_enabled = testAttribute(LocalStorageEnabled); - prefs->allow_universal_access_from_file_urls = testAttribute(LocalContentCanAccessRemoteUrls); - prefs->spatial_navigation_enabled = testAttribute(SpatialNavigationEnabled); - prefs->allow_file_access_from_file_urls = testAttribute(LocalContentCanAccessFileUrls); - prefs->hyperlink_auditing_enabled = testAttribute(HyperlinkAuditingEnabled); - prefs->enable_scroll_animator = testAttribute(ScrollAnimatorEnabled); - prefs->enable_error_page = testAttribute(ErrorPageEnabled); - prefs->plugins_enabled = testAttribute(PluginsEnabled); - prefs->fullscreen_supported = testAttribute(FullScreenSupportEnabled); - prefs->accelerated_2d_canvas_enabled = testAttribute(Accelerated2dCanvasEnabled); - prefs->webgl1_enabled = prefs->webgl2_enabled = testAttribute(WebGLEnabled); - prefs->should_print_backgrounds = testAttribute(PrintElementBackgrounds); - prefs->allow_running_insecure_content = testAttribute(AllowRunningInsecureContent); - prefs->allow_geolocation_on_insecure_origins = testAttribute(AllowGeolocationOnInsecureOrigins); - prefs->hide_scrollbars = !testAttribute(ShowScrollBars); - if (isAttributeExplicitlySet(PlaybackRequiresUserGesture)) { - prefs->autoplay_policy = testAttribute(PlaybackRequiresUserGesture) - ? content::AutoplayPolicy::kUserGestureRequired - : content::AutoplayPolicy::kNoUserGestureRequired; + prefs->loads_images_automatically = testAttribute(QWebEngineSettings::AutoLoadImages); + prefs->javascript_enabled = testAttribute(QWebEngineSettings::JavascriptEnabled); + prefs->javascript_can_access_clipboard = + testAttribute(QWebEngineSettings::JavascriptCanAccessClipboard); + prefs->tabs_to_links = testAttribute(QWebEngineSettings::LinksIncludedInFocusChain); + prefs->local_storage_enabled = testAttribute(QWebEngineSettings::LocalStorageEnabled); + prefs->databases_enabled = testAttribute(QWebEngineSettings::LocalStorageEnabled); + prefs->allow_universal_access_from_file_urls = + testAttribute(QWebEngineSettings::LocalContentCanAccessRemoteUrls); + prefs->spatial_navigation_enabled = testAttribute(QWebEngineSettings::SpatialNavigationEnabled); + prefs->allow_file_access_from_file_urls = + testAttribute(QWebEngineSettings::LocalContentCanAccessFileUrls); + prefs->hyperlink_auditing_enabled = testAttribute(QWebEngineSettings::HyperlinkAuditingEnabled); + prefs->enable_scroll_animator = testAttribute(QWebEngineSettings::ScrollAnimatorEnabled); + prefs->enable_error_page = testAttribute(QWebEngineSettings::ErrorPageEnabled); + prefs->plugins_enabled = testAttribute(QWebEngineSettings::PluginsEnabled); + prefs->fullscreen_supported = testAttribute(QWebEngineSettings::FullScreenSupportEnabled); + prefs->accelerated_2d_canvas_enabled = + testAttribute(QWebEngineSettings::Accelerated2dCanvasEnabled); + prefs->webgl1_enabled = prefs->webgl2_enabled = testAttribute(QWebEngineSettings::WebGLEnabled); + prefs->should_print_backgrounds = testAttribute(QWebEngineSettings::PrintElementBackgrounds); + prefs->allow_running_insecure_content = + testAttribute(QWebEngineSettings::AllowRunningInsecureContent); + prefs->allow_geolocation_on_insecure_origins = + testAttribute(QWebEngineSettings::AllowGeolocationOnInsecureOrigins); + prefs->hide_scrollbars = !testAttribute(QWebEngineSettings::ShowScrollBars); + if (isAttributeExplicitlySet(QWebEngineSettings::PlaybackRequiresUserGesture)) { + prefs->autoplay_policy = testAttribute(QWebEngineSettings::PlaybackRequiresUserGesture) + ? content::AutoplayPolicy::kUserGestureRequired + : content::AutoplayPolicy::kNoUserGestureRequired; } - prefs->dom_paste_enabled = testAttribute(JavascriptCanPaste); - prefs->dns_prefetching_enabled = testAttribute(DnsPrefetchEnabled); + prefs->dom_paste_enabled = testAttribute(QWebEngineSettings::JavascriptCanPaste); + prefs->dns_prefetching_enabled = testAttribute(QWebEngineSettings::DnsPrefetchEnabled); // Fonts settings. - prefs->standard_font_family_map[content::kCommonScript] = toString16(fontFamily(StandardFont)); - prefs->fixed_font_family_map[content::kCommonScript] = toString16(fontFamily(FixedFont)); - prefs->serif_font_family_map[content::kCommonScript] = toString16(fontFamily(SerifFont)); - prefs->sans_serif_font_family_map[content::kCommonScript] = toString16(fontFamily(SansSerifFont)); - prefs->cursive_font_family_map[content::kCommonScript] = toString16(fontFamily(CursiveFont)); - prefs->fantasy_font_family_map[content::kCommonScript] = toString16(fontFamily(FantasyFont)); - prefs->pictograph_font_family_map[content::kCommonScript] = toString16(fontFamily(PictographFont)); - prefs->default_font_size = fontSize(DefaultFontSize); - prefs->default_fixed_font_size = fontSize(DefaultFixedFontSize); - prefs->minimum_font_size = fontSize(MinimumFontSize); - prefs->minimum_logical_font_size = fontSize(MinimumLogicalFontSize); + prefs->standard_font_family_map[content::kCommonScript] = + toString16(fontFamily(QWebEngineSettings::StandardFont)); + prefs->fixed_font_family_map[content::kCommonScript] = + toString16(fontFamily(QWebEngineSettings::FixedFont)); + prefs->serif_font_family_map[content::kCommonScript] = + toString16(fontFamily(QWebEngineSettings::SerifFont)); + prefs->sans_serif_font_family_map[content::kCommonScript] = + toString16(fontFamily(QWebEngineSettings::SansSerifFont)); + prefs->cursive_font_family_map[content::kCommonScript] = + toString16(fontFamily(QWebEngineSettings::CursiveFont)); + prefs->fantasy_font_family_map[content::kCommonScript] = + toString16(fontFamily(QWebEngineSettings::FantasyFont)); + prefs->pictograph_font_family_map[content::kCommonScript] = + toString16(fontFamily(QWebEngineSettings::PictographFont)); + prefs->default_font_size = fontSize(QWebEngineSettings::DefaultFontSize); + prefs->default_fixed_font_size = fontSize(QWebEngineSettings::DefaultFixedFontSize); + prefs->minimum_font_size = fontSize(QWebEngineSettings::MinimumFontSize); + prefs->minimum_logical_font_size = fontSize(QWebEngineSettings::MinimumLogicalFontSize); prefs->default_encoding = defaultTextEncoding().toStdString(); // Set the theme colors. Based on chrome_content_browser_client.cc: @@ -454,9 +472,10 @@ bool WebEngineSettings::applySettingsToRendererPreferences(blink::mojom::Rendere bool changed = false; #if QT_CONFIG(webengine_webrtc) if (!base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kForceWebRtcIPHandlingPolicy)) { - std::string webrtc_ip_handling_policy = testAttribute(WebEngineSettings::WebRTCPublicInterfacesOnly) - ? blink::kWebRTCIPHandlingDefaultPublicInterfaceOnly - : blink::kWebRTCIPHandlingDefault; + std::string webrtc_ip_handling_policy = + testAttribute(QWebEngineSettings::WebRTCPublicInterfacesOnly) + ? blink::kWebRTCIPHandlingDefaultPublicInterfaceOnly + : blink::kWebRTCIPHandlingDefault; if (prefs->webrtc_ip_handling_policy != webrtc_ip_handling_policy) { prefs->webrtc_ip_handling_policy = webrtc_ip_handling_policy; changed = true; @@ -476,7 +495,7 @@ void WebEngineSettings::scheduleApplyRecursively() bool WebEngineSettings::getJavaScriptCanOpenWindowsAutomatically() { - return testAttribute(JavascriptCanOpenWindows); + return testAttribute(QWebEngineSettings::JavascriptCanOpenWindows); } void WebEngineSettings::setParentSettings(WebEngineSettings *_parentSettings) @@ -486,6 +505,7 @@ void WebEngineSettings::setParentSettings(WebEngineSettings *_parentSettings) parentSettings = _parentSettings; if (parentSettings) parentSettings->childSettings.insert(this); + scheduleApplyRecursively(); } } // namespace QtWebEngineCore diff --git a/src/core/web_engine_settings.h b/src/core/web_engine_settings.h index 95eea669f..5be72005a 100644 --- a/src/core/web_engine_settings.h +++ b/src/core/web_engine_settings.h @@ -52,7 +52,7 @@ #define WEB_ENGINE_SETTINGS_H #include "qtwebenginecoreglobal_p.h" - +#include "qwebenginesettings.h" #include <QScopedPointer> #include <QHash> #include <QUrl> @@ -72,98 +72,36 @@ namespace QtWebEngineCore { class WebContentsAdapter; -class Q_WEBENGINECORE_PRIVATE_EXPORT WebEngineSettings { +class WebEngineSettings { public: - // Attributes. Names match the ones from the public widgets API. - enum Attribute { - UnsupportedInCoreSettings = -1, - AutoLoadImages, - JavascriptEnabled, - JavascriptCanOpenWindows, - JavascriptCanAccessClipboard, - LinksIncludedInFocusChain, - LocalStorageEnabled, - LocalContentCanAccessRemoteUrls, - XSSAuditingEnabled, - SpatialNavigationEnabled, - LocalContentCanAccessFileUrls, - HyperlinkAuditingEnabled, - ScrollAnimatorEnabled, - ErrorPageEnabled, - PluginsEnabled, - FullScreenSupportEnabled, - ScreenCaptureEnabled, - WebGLEnabled, - Accelerated2dCanvasEnabled, - AutoLoadIconsForPage, - TouchIconsEnabled, - FocusOnNavigationEnabled, - PrintElementBackgrounds, - AllowRunningInsecureContent, - AllowGeolocationOnInsecureOrigins, - AllowWindowActivationFromJavaScript, - ShowScrollBars, - PlaybackRequiresUserGesture, - WebRTCPublicInterfacesOnly, - JavascriptCanPaste, - DnsPrefetchEnabled, - PdfViewerEnabled, - }; - - // Must match the values from the public API in qwebenginesettings.h. - enum FontFamily { - StandardFont, - FixedFont, - SerifFont, - SansSerifFont, - CursiveFont, - FantasyFont, - PictographFont - }; - - // Must match the values from the public API in qwebenginesettings.h. - enum FontSize { - MinimumFontSize, - MinimumLogicalFontSize, - DefaultFontSize, - DefaultFixedFontSize - }; - - // Must match the values from the public API in qwebenginesettings.h. - enum UnknownUrlSchemePolicy { - InheritedUnknownUrlSchemePolicy = 0, - DisallowUnknownUrlSchemes = 1, - AllowUnknownUrlSchemesFromUserInteraction, - AllowAllUnknownUrlSchemes - }; - - explicit WebEngineSettings(WebEngineSettings *parentSettings = 0); + static WebEngineSettings* get(QWebEngineSettings *settings) { return settings->d_ptr.data(); } + + explicit WebEngineSettings(WebEngineSettings *parentSettings = nullptr); ~WebEngineSettings(); void setParentSettings(WebEngineSettings *parentSettings); void overrideWebPreferences(content::WebContents *webContents, content::WebPreferences *prefs); - void setAttribute(Attribute, bool on); - bool testAttribute(Attribute) const; - void resetAttribute(Attribute); - bool isAttributeExplicitlySet(Attribute) const; + void setAttribute(QWebEngineSettings::WebAttribute, bool on); + bool testAttribute(QWebEngineSettings::WebAttribute) const; + void resetAttribute(QWebEngineSettings::WebAttribute); + bool isAttributeExplicitlySet(QWebEngineSettings::WebAttribute) const; - void setFontFamily(FontFamily, const QString &); - QString fontFamily(FontFamily); - void resetFontFamily(FontFamily); + void setFontFamily(QWebEngineSettings::FontFamily, const QString &); + QString fontFamily(QWebEngineSettings::FontFamily); + void resetFontFamily(QWebEngineSettings::FontFamily); - void setFontSize(FontSize type, int size); - int fontSize(FontSize type) const; - void resetFontSize(FontSize type); + void setFontSize(QWebEngineSettings::FontSize type, int size); + int fontSize(QWebEngineSettings::FontSize type) const; + void resetFontSize(QWebEngineSettings::FontSize type); void setDefaultTextEncoding(const QString &encoding); QString defaultTextEncoding() const; - void setUnknownUrlSchemePolicy(UnknownUrlSchemePolicy policy); - UnknownUrlSchemePolicy unknownUrlSchemePolicy() const; + void setUnknownUrlSchemePolicy(QWebEngineSettings::UnknownUrlSchemePolicy policy); + QWebEngineSettings::UnknownUrlSchemePolicy unknownUrlSchemePolicy() const; - void initDefaults(); void scheduleApply(); void scheduleApplyRecursively(); @@ -171,15 +109,16 @@ public: bool getJavaScriptCanOpenWindowsAutomatically(); private: + void initDefaults(); void doApply(); void applySettingsToWebPreferences(content::WebPreferences *); bool applySettingsToRendererPreferences(blink::mojom::RendererPreferences *); void setWebContentsAdapter(WebContentsAdapter *adapter) { m_adapter = adapter; } WebContentsAdapter* m_adapter; - QHash<Attribute, bool> m_attributes; - QHash<FontFamily, QString> m_fontFamilies; - QHash<FontSize, int> m_fontSizes; + QHash<QWebEngineSettings::WebAttribute, bool> m_attributes; + QHash<QWebEngineSettings::FontFamily, QString> m_fontFamilies; + QHash<QWebEngineSettings::FontSize, int> m_fontSizes; QString m_defaultEncoding; QScopedPointer<content::WebPreferences> webPreferences; QTimer m_batchTimer; @@ -187,10 +126,10 @@ private: WebEngineSettings *parentSettings; QSet<WebEngineSettings *> childSettings; - static QHash<Attribute, bool> s_defaultAttributes; - static QHash<FontFamily, QString> s_defaultFontFamilies; - static QHash<FontSize, int> s_defaultFontSizes; - UnknownUrlSchemePolicy m_unknownUrlSchemePolicy; + static QHash<QWebEngineSettings::WebAttribute, bool> s_defaultAttributes; + static QHash<QWebEngineSettings::FontFamily, QString> s_defaultFontFamilies; + static QHash<QWebEngineSettings::FontSize, int> s_defaultFontSizes; + QWebEngineSettings::UnknownUrlSchemePolicy m_unknownUrlSchemePolicy; friend class WebContentsAdapter; }; diff --git a/src/core/web_event_factory.cpp b/src/core/web_event_factory.cpp index 798ee9633..e77463930 100644 --- a/src/core/web_event_factory.cpp +++ b/src/core/web_event_factory.cpp @@ -82,7 +82,7 @@ #include <QMouseEvent> #include <QStyleHints> #if QT_CONFIG(tabletevent) -#include <QTabletEvent> +#include <QPointingDevice> #endif #include <QWheelEvent> @@ -1419,12 +1419,14 @@ static WebInputEvent::Type webEventTypeForEvent(const QEvent* event) static WebPointerProperties::PointerType pointerTypeForTabletEvent(const QTabletEvent *ev) { switch (ev->pointerType()) { - case QTabletEvent::UnknownPointer: + case QPointingDevice::PointerType::Unknown: return WebPointerProperties::PointerType::kUnknown; - case QTabletEvent::Pen: + case QPointingDevice::PointerType::Pen: return WebPointerProperties::PointerType::kPen; - case QTabletEvent::Eraser: + case QPointingDevice::PointerType::Eraser: return WebPointerProperties::PointerType::kEraser; + case QPointingDevice::PointerType::Finger: + return WebPointerProperties::PointerType::kTouch; default: return WebPointerProperties::PointerType::kMouse; } @@ -1434,8 +1436,8 @@ static WebPointerProperties::PointerType pointerTypeForTabletEvent(const QTablet WebMouseEvent WebEventFactory::toWebMouseEvent(QMouseEvent *ev) { WebMouseEvent webKitEvent(webEventTypeForEvent(ev), - gfx::PointF(ev->x(), ev->y()), - gfx::PointF(ev->globalX(), ev->globalY()), + gfx::PointF(ev->position().x(), ev->position().y()), + gfx::PointF(ev->globalPosition().x(), ev->globalPosition().y()), mouseButtonForEvent<QMouseEvent>(ev), 0, modifiersForEvent(ev), @@ -1453,9 +1455,9 @@ WebMouseEvent WebEventFactory::toWebMouseEvent(QHoverEvent *ev) webKitEvent.SetModifiers(modifiersForEvent(ev)); webKitEvent.SetType(webEventTypeForEvent(ev)); - 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.SetPositionInWidget(ev->position().x(), ev->position().y()); + webKitEvent.movement_x = ev->position().x() - ev->oldPos().x(); + webKitEvent.movement_y = ev->position().y() - ev->oldPos().y(); webKitEvent.pointer_type = WebPointerProperties::PointerType::kMouse; return webKitEvent; @@ -1465,8 +1467,8 @@ WebMouseEvent WebEventFactory::toWebMouseEvent(QHoverEvent *ev) WebMouseEvent WebEventFactory::toWebMouseEvent(QTabletEvent *ev) { WebMouseEvent webKitEvent(webEventTypeForEvent(ev), - gfx::PointF(ev->x(), ev->y()), - gfx::PointF(ev->globalX(), ev->globalY()), + gfx::PointF(ev->position().x(), ev->position().y()), + gfx::PointF(ev->globalPosition().x(), ev->globalPosition().y()), mouseButtonForEvent<QTabletEvent>(ev), 0, modifiersForEvent(ev), @@ -1499,9 +1501,11 @@ WebGestureEvent WebEventFactory::toWebGestureEvent(QNativeGestureEvent *ev) webKitEvent.SetTimeStamp(base::TimeTicks::Now()); webKitEvent.SetModifiers(modifiersForEvent(ev)); - webKitEvent.SetPositionInWidget(gfx::PointF(ev->localPos().x(), ev->localPos().y())); + webKitEvent.SetPositionInWidget(gfx::PointF(ev->position().x(), + ev->position().y())); - webKitEvent.SetPositionInScreen(gfx::PointF(ev->screenPos().x(), ev->screenPos().y())); + webKitEvent.SetPositionInScreen(gfx::PointF(ev->globalPosition().x(), + ev->globalPosition().y())); webKitEvent.SetSourceDevice(blink::WebGestureDevice::kTouchpad); |