diff options
Diffstat (limited to 'src')
38 files changed, 402 insertions, 276 deletions
diff --git a/src/3rdparty b/src/3rdparty -Subproject 0c43a097b39603be90162b519927a7e47f15ae9 +Subproject 4368c7380883fd6b32d913d27a5b8f51f615068 diff --git a/src/buildtools/configure_host.pro b/src/buildtools/configure_host.pro index f1b3d47b0..dd0d3e327 100644 --- a/src/buildtools/configure_host.pro +++ b/src/buildtools/configure_host.pro @@ -23,6 +23,8 @@ contains(GN_TARGET_CPU, "arm")|contains(GN_TARGET_CPU, "mipsel")|contains(GN_TAR else: contains(GN_V8_HOST_CPU, mips64el): GN_V8_HOST_CPU = "mipsel" } +GN_HOST_EXTRA_CPPFLAGS = $$(GN_HOST_TOOLCHAIN_EXTRA_CPPFLAGS) + # We always use the gcc_toolchain, because clang_toolchain is just # a broken wrapper around it for Google's custom clang binaries. GN_CONTENTS = \ @@ -34,6 +36,7 @@ GN_CONTENTS = \ " ld = \"$$which($$QMAKE_LINK)\" " \ " ar = \"$$which(ar)\" " \ " nm = \"$$which(nm)\" " \ +" extra_cppflags = \"$$GN_HOST_EXTRA_CPPFLAGS\" " \ " toolchain_args = { " \ " current_os = \"$$GN_OS\" " \ " current_cpu = \"$$GN_HOST_CPU\" " \ diff --git a/src/buildtools/gn.pro b/src/buildtools/gn.pro index 9d9af9eb8..f66f4bd68 100644 --- a/src/buildtools/gn.pro +++ b/src/buildtools/gn.pro @@ -7,11 +7,11 @@ include($$QTWEBENGINE_OUT_ROOT/qtwebengine-config.pri) QT_FOR_CONFIG += webengine webengine-private build_pass|!debug_and_release { - !qtConfig(system-gn): CONFIG(release, debug|release) { + !qtConfig(webengine-system-gn): CONFIG(release, debug|release) { buildgn.target = build_gn gn_args = $$gnArgs() out = $$gnPath() - !qtConfig(system-ninja): ninja_path = "--path $$ninjaPath()" + !qtConfig(webengine-system-ninja): ninja_path = "--path $$ninjaPath()" # check if it is not already build !exists($$out) { mkpath($$dirname(out)) diff --git a/src/buildtools/ninja.pro b/src/buildtools/ninja.pro index c99513f85..1b15bcb6b 100644 --- a/src/buildtools/ninja.pro +++ b/src/buildtools/ninja.pro @@ -7,7 +7,7 @@ QT_FOR_CONFIG += webengine-private build_pass|!debug_and_release { - !qtConfig(system-ninja): CONFIG(release, debug|release) { + !qtConfig(webengine-system-ninja): CONFIG(release, debug|release) { out = $$ninjaPath() # check if it is not already build !exists($$out) { diff --git a/src/core/config/common.pri b/src/core/config/common.pri index e7010a13a..d8a4fa181 100644 --- a/src/core/config/common.pri +++ b/src/core/config/common.pri @@ -12,9 +12,10 @@ gn_args += \ v8_use_external_startup_data=false \ treat_warnings_as_errors=false \ enable_swiftshader=false \ - use_custom_libcxx=false + use_custom_libcxx=false \ + use_jumbo_build=true -qtConfig(printing-and-pdf) { +qtConfig(webengine-printing-and-pdf) { gn_args += enable_basic_printing=true enable_print_preview=true gn_args += enable_pdf=true } else { @@ -22,25 +23,25 @@ qtConfig(printing-and-pdf) { gn_args += enable_pdf=false } -qtConfig(pepper-plugins) { +qtConfig(webengine-pepper-plugins) { gn_args += enable_plugins=true enable_widevine=true } else { gn_args += enable_plugins=false enable_widevine=false } -qtConfig(spellchecker) { +qtConfig(webengine-spellchecker) { gn_args += enable_spellcheck=true } else { gn_args += enable_spellcheck=false } -qtConfig(webrtc) { +qtConfig(webengine-webrtc) { gn_args += enable_webrtc=true } else { gn_args += enable_webrtc=false } -qtConfig(proprietary-codecs): gn_args += proprietary_codecs=true ffmpeg_branding=\"Chrome\" +qtConfig(webengine-proprietary-codecs): gn_args += proprietary_codecs=true ffmpeg_branding=\"Chrome\" CONFIG(release, debug|release) { force_debug_info { diff --git a/src/core/config/linux.pri b/src/core/config/linux.pri index 78f3e5093..6f7b27f10 100644 --- a/src/core/config/linux.pri +++ b/src/core/config/linux.pri @@ -112,23 +112,26 @@ host_build { # Strip '>2 /dev/null' from $$pkgConfigExecutable() PKGCONFIG = $$first($$list($$pkgConfigExecutable())) gn_args += pkg_config=\"$$PKGCONFIG\" - gn_args += host_pkg_config=\"pkg-config\" + PKG_CONFIG_HOST = $$(GN_PKG_CONFIG_HOST) + isEmpty(PKG_CONFIG_HOST): PKG_CONFIG_HOST = pkg-config + gn_args += host_pkg_config=\"$$PKG_CONFIG_HOST\" } - qtConfig(webengine-system-zlib): qtConfig(system-minizip) { + qtConfig(webengine-system-zlib): qtConfig(webengine-system-minizip) { gn_args += use_system_zlib=true use_system_minizip=true + qtConfig(webengine-printing-and-pdf): gn_args += pdfium_use_system_zlib=true } qtConfig(webengine-system-png): gn_args += use_system_libpng=true qtConfig(system-jpeg): gn_args += use_system_libjpeg=true qtConfig(system-freetype): gn_args += use_system_freetype=true qtConfig(webengine-system-harfbuzz): gn_args += use_system_harfbuzz=true - qtConfig(system-glib): gn_args += use_glib=false - qtConfig(pulseaudio) { + qtConfig(webengine-system-glib): gn_args += use_glib=false + qtConfig(webengine-pulseaudio) { gn_args += use_pulseaudio=true } else { gn_args += use_pulseaudio=false } - qtConfig(alsa) { + qtConfig(webengine-alsa) { gn_args += use_alsa=true } else { gn_args += use_alsa=false @@ -138,18 +141,19 @@ host_build { !packagesExist(libpci): gn_args += use_libpci=false !packagesExist(xscrnsaver): gn_args += use_xscrnsaver=false - qtConfig(system-libevent): gn_args += use_system_libevent=true - qtConfig(system-libwebp): gn_args += use_system_libwebp=true - qtConfig(system-libxml2): gn_args += use_system_libxml=true use_system_libxslt=true - qtConfig(system-opus): gn_args += use_system_opus=true - qtConfig(system-snappy): gn_args += use_system_snappy=true - qtConfig(system-libvpx): gn_args += use_system_libvpx=true - qtConfig(system-icu): gn_args += use_system_icu=true icu_use_data_file=false - qtConfig(system-ffmpeg): gn_args += use_system_ffmpeg=true - qtConfig(system-re2): gn_args += use_system_re2=true + qtConfig(webengine-system-libevent): gn_args += use_system_libevent=true + qtConfig(webengine-system-libwebp): gn_args += use_system_libwebp=true + qtConfig(webengine-system-libxml2): gn_args += use_system_libxml=true use_system_libxslt=true + qtConfig(webengine-system-opus): gn_args += use_system_opus=true + qtConfig(webengine-system-snappy): gn_args += use_system_snappy=true + qtConfig(webengine-system-libvpx): gn_args += use_system_libvpx=true + qtConfig(webengine-system-icu): gn_args += use_system_icu=true icu_use_data_file=false + qtConfig(webengine-system-ffmpeg): gn_args += use_system_ffmpeg=true + qtConfig(webengine-system-re2): gn_args += use_system_re2=true + qtConfig(webengine-system-lcms2): gn_args += use_system_lcms2=true # FIXME: - #qtConfig(system-protobuf): gn_args += use_system_protobuf=true - #qtConfig(system-jsoncpp): gn_args += use_system_jsoncpp=true - #qtConfig(system-libsrtp: gn_args += use_system_libsrtp=true + #qtConfig(webengine-system-protobuf): gn_args += use_system_protobuf=true + #qtConfig(webengine-system-jsoncpp): gn_args += use_system_jsoncpp=true + #qtConfig(webengine-system-libsrtp: gn_args += use_system_libsrtp=true } diff --git a/src/core/config/mac_osx.pri b/src/core/config/mac_osx.pri index 57f301f18..2d820c889 100644 --- a/src/core/config/mac_osx.pri +++ b/src/core/config/mac_osx.pri @@ -32,8 +32,8 @@ gn_args += \ toolkit_views=false \ use_external_popup_menu=false -qtConfig(spellchecker) { - qtConfig(native-spellchecker): gn_args += use_browser_spellchecker=true +qtConfig(webengine-spellchecker) { + qtConfig(webengine-native-spellchecker): gn_args += use_browser_spellchecker=true else: gn_args += use_browser_spellchecker=false } else { gn_args += use_browser_spellchecker=false diff --git a/src/core/content_client_qt.cpp b/src/core/content_client_qt.cpp index 1016db0d5..a3a460cb4 100644 --- a/src/core/content_client_qt.cpp +++ b/src/core/content_client_qt.cpp @@ -236,6 +236,7 @@ void AddPepperWidevine(std::vector<content::PepperPluginInfo>* plugins) #elif defined(Q_OS_LINUX) pluginPaths << QStringLiteral("/opt/google/chrome/libwidevinecdmadapter.so") // Google Chrome << QStringLiteral("/usr/lib/chromium/libwidevinecdmadapter.so") // Arch + << QStringLiteral("/usr/lib/chromium-browser/libwidevinecdmadapter.so") // Ubuntu/neon << QStringLiteral("/usr/lib64/chromium/libwidevinecdmadapter.so"); // OpenSUSE style #endif } @@ -257,7 +258,7 @@ void AddPepperWidevine(std::vector<content::PepperPluginInfo>* plugins) std::vector<std::string> codecs; codecs.push_back(kCdmSupportedCodecVp8); codecs.push_back(kCdmSupportedCodecVp9); -#if defined(USE_PROPRIETARY_CODECS) +#if BUILDFLAG(USE_PROPRIETARY_CODECS) codecs.push_back(kCdmSupportedCodecAvc1); #endif // defined(USE_PROPRIETARY_CODECS) std::string codec_string = diff --git a/src/core/core_chromium.pri b/src/core/core_chromium.pri index 179266900..513cd4c1f 100644 --- a/src/core/core_chromium.pri +++ b/src/core/core_chromium.pri @@ -28,7 +28,7 @@ RCC_DIR = $$OUT_PWD/$$getConfigDir()/.rcc # Assume that we want mobile touch and low-end hardware behaviors # whenever we are cross compiling. -qtConfig(embedded): DEFINES += QTWEBENGINE_EMBEDDED_SWITCHES +qtConfig(webengine-embedded-build): DEFINES += QTWEBENGINE_EMBEDDED_SWITCHES qtConfig(egl): CONFIG += egl @@ -79,7 +79,6 @@ SOURCES = \ quota_permission_controller.cpp \ render_view_observer_host_qt.cpp \ render_widget_host_view_qt.cpp \ - render_widget_host_view_qt_delegate.cpp \ renderer/content_renderer_client_qt.cpp \ renderer/render_frame_observer_qt.cpp \ renderer/render_view_observer_qt.cpp \ @@ -192,7 +191,7 @@ HEADERS = \ web_event_factory.h \ webui/webui_controller_factory_qt.h -qtConfig(pepper-plugins) { +qtConfig(webengine-pepper-plugins) { SOURCES += \ renderer_host/pepper/pepper_flash_browser_host_qt.cpp \ @@ -209,7 +208,7 @@ qtConfig(pepper-plugins) { renderer/pepper/pepper_renderer_host_factory_qt.h } -qtConfig(printing-and-pdf) { +qtConfig(webengine-printing-and-pdf) { SOURCES += \ printing_message_filter_qt.cpp \ diff --git a/src/core/core_module.pro b/src/core/core_module.pro index 78bb8baee..2409ccb12 100644 --- a/src/core/core_module.pro +++ b/src/core/core_module.pro @@ -115,7 +115,7 @@ icu.files = $$OUT_PWD/$$getConfigDir()/icudtl.dat resources.path = $$[QT_INSTALL_DATA]/resources INSTALLS += locales resources - !qtConfig(system-icu) { + !qtConfig(webengine-system-icu) { icu.CONFIG += no_check_exist icu.path = $$[QT_INSTALL_DATA]/resources INSTALLS += icu @@ -127,7 +127,7 @@ icu.files = $$OUT_PWD/$$getConfigDir()/icudtl.dat # Copy essential files to the qtbase build directory for non-prefix builds # - !qtConfig(system-icu) { + !qtConfig(webengine-system-icu) { COPIES += icu } diff --git a/src/core/delegated_frame_node.cpp b/src/core/delegated_frame_node.cpp index d6ee87950..6f4a4e8db 100644 --- a/src/core/delegated_frame_node.cpp +++ b/src/core/delegated_frame_node.cpp @@ -218,14 +218,8 @@ public: void setupRenderPassNode(QSGTexture *layer, const QRect &rect, QSGNode *) override { + Q_ASSERT(layer); QSGInternalImageNode *imageNode = static_cast<QSGInternalImageNode*>(*m_nodeIterator++); - // In case of a missing render pass, set the target rects to be empty and return early. - // cc::GLRenderer::DrawRenderPassQuad silently ignores missing render passes - if (!layer) { - imageNode->setTargetRect(QRect()); - imageNode->setInnerTargetRect(QRect()); - return; - } imageNode->setTargetRect(rect); imageNode->setInnerTargetRect(rect); imageNode->setTexture(layer); @@ -320,23 +314,16 @@ public: void setupRenderPassNode(QSGTexture *layer, const QRect &rect, QSGNode *layerChain) override { + Q_ASSERT(layer); // Only QSGInternalImageNode currently supports QSGLayer textures. QSGInternalImageNode *imageNode = m_apiDelegate->createImageNode(); - layerChain->appendChildNode(imageNode); - m_sceneGraphNodes->append(imageNode); - - // In case of a missing render pass, set the target rects to be empty and return early. - // cc::GLRenderer::DrawRenderPassQuad silently ignores missing render passes - if (!layer) { - imageNode->setTargetRect(QRect()); - imageNode->setInnerTargetRect(QRect()); - return; - } - imageNode->setTargetRect(rect); imageNode->setInnerTargetRect(rect); imageNode->setTexture(layer); imageNode->update(); + + layerChain->appendChildNode(imageNode); + m_sceneGraphNodes->append(imageNode); } void setupTextureContentNode(QSGTexture *texture, const QRect &rect, const QRectF &sourceRect, @@ -1110,7 +1097,8 @@ void DelegatedFrameNode::handleQuad( QSGTexture *layer = findRenderPassLayer(renderPassQuad->render_pass_id, m_sgObjects.renderPassLayers).data(); - nodeHandler->setupRenderPassNode(layer, toQt(quad->rect), currentLayerChain); + if (layer) + nodeHandler->setupRenderPassNode(layer, toQt(quad->rect), currentLayerChain); break; } case cc::DrawQuad::TEXTURE_CONTENT: { @@ -1263,6 +1251,8 @@ void DelegatedFrameNode::fetchAndSyncMailboxes(QList<MailboxTexture *> &mailboxe QList<gl::TransferableFence> transferredFences; { QMutexLocker lock(&m_mutex); + QVector<MailboxTexture *> mailboxesToPull; + mailboxesToPull.reserve(mailboxesToFetch.size()); gpu::SyncPointManager *syncPointManager = sync_point_manager(); base::MessageLoop *gpuMessageLoop = gpu_message_loop(); @@ -1271,9 +1261,12 @@ void DelegatedFrameNode::fetchAndSyncMailboxes(QList<MailboxTexture *> &mailboxe for (MailboxTexture *mailboxTexture : qAsConst(mailboxesToFetch)) { gpu::SyncToken &syncToken = mailboxTexture->mailboxHolder().sync_token; const auto task = base::Bind(&DelegatedFrameNode::pullTexture, this, mailboxTexture); - if (syncPointManager->WaitOutOfOrderNonThreadSafe(syncToken, gpuMessageLoop->task_runner(), task)) - continue; - gpuMessageLoop->task_runner()->PostTask(FROM_HERE, task); + if (!syncPointManager->WaitOutOfOrderNonThreadSafe(syncToken, gpuMessageLoop->task_runner(), std::move(task))) + mailboxesToPull.append(mailboxTexture); + } + if (!mailboxesToPull.isEmpty()) { + auto task = base::BindOnce(&DelegatedFrameNode::pullTextures, this, std::move(mailboxesToPull)); + gpuMessageLoop->task_runner()->PostTask(FROM_HERE, std::move(task)); } m_mailboxesFetchedWaitCond.wait(&m_mutex); @@ -1349,6 +1342,25 @@ void DelegatedFrameNode::fetchAndSyncMailboxes(QList<MailboxTexture *> &mailboxe } +void DelegatedFrameNode::pullTextures(DelegatedFrameNode *frameNode, const QVector<MailboxTexture *> textures) +{ +#ifndef QT_NO_OPENGL + gpu::gles2::MailboxManager *mailboxManager = mailbox_manager(); + for (MailboxTexture *texture : textures) { + gpu::SyncToken &syncToken = texture->mailboxHolder().sync_token; + if (syncToken.HasData()) + mailboxManager->PullTextureUpdates(syncToken); + texture->fetchTexture(mailboxManager); + --frameNode->m_numPendingSyncPoints; + } + + fenceAndUnlockQt(frameNode); +#else + Q_UNUSED(frameNode) + Q_UNUSED(textures) +#endif +} + void DelegatedFrameNode::pullTexture(DelegatedFrameNode *frameNode, MailboxTexture *texture) { #ifndef QT_NO_OPENGL @@ -1357,6 +1369,18 @@ void DelegatedFrameNode::pullTexture(DelegatedFrameNode *frameNode, MailboxTextu if (syncToken.HasData()) mailboxManager->PullTextureUpdates(syncToken); texture->fetchTexture(mailboxManager); + --frameNode->m_numPendingSyncPoints; + + fenceAndUnlockQt(frameNode); +#else + Q_UNUSED(frameNode) + Q_UNUSED(texture) +#endif +} + +void DelegatedFrameNode::fenceAndUnlockQt(DelegatedFrameNode *frameNode) +{ +#ifndef QT_NO_OPENGL if (!!gl::GLContext::GetCurrent() && gl::GLFence::IsSupported()) { // Create a fence on the Chromium GPU-thread and context gl::GLFence *fence = gl::GLFence::Create(); @@ -1364,15 +1388,14 @@ void DelegatedFrameNode::pullTexture(DelegatedFrameNode *frameNode, MailboxTextu frameNode->m_textureFences.append(fence->Transfer()); delete fence; } - if (--frameNode->m_numPendingSyncPoints == 0) - base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, base::Bind(&DelegatedFrameNode::fenceAndUnlockQt, frameNode)); + if (frameNode->m_numPendingSyncPoints == 0) + base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, base::Bind(&DelegatedFrameNode::unlockQt, frameNode)); #else Q_UNUSED(frameNode) - Q_UNUSED(texture) #endif } -void DelegatedFrameNode::fenceAndUnlockQt(DelegatedFrameNode *frameNode) +void DelegatedFrameNode::unlockQt(DelegatedFrameNode *frameNode) { QMutexLocker lock(&frameNode->m_mutex); // Signal preprocess() the textures are ready diff --git a/src/core/delegated_frame_node.h b/src/core/delegated_frame_node.h index c627cdf95..4bddf4a62 100644 --- a/src/core/delegated_frame_node.h +++ b/src/core/delegated_frame_node.h @@ -123,7 +123,9 @@ private: // Making those callbacks static bypasses base::Bind's ref-counting requirement // of the this pointer when the callback is a method. static void pullTexture(DelegatedFrameNode *frameNode, MailboxTexture *mailbox); + static void pullTextures(DelegatedFrameNode *frameNode, const QVector<MailboxTexture *> mailboxes); static void fenceAndUnlockQt(DelegatedFrameNode *frameNode); + static void unlockQt(DelegatedFrameNode *frameNode); ResourceHolder *findAndHoldResource(unsigned resourceId, QHash<unsigned, QSharedPointer<ResourceHolder> > &candidates); void holdResources(const cc::DrawQuad *quad, QHash<unsigned, QSharedPointer<ResourceHolder> > &candidates); diff --git a/src/core/gn_run.pro b/src/core/gn_run.pro index a9089c569..dbf859100 100644 --- a/src/core/gn_run.pro +++ b/src/core/gn_run.pro @@ -5,7 +5,7 @@ TEMPLATE = aux qtConfig(debug_and_release): CONFIG += debug_and_release build_all -qtConfig(system-ninja) { +qtConfig(webengine-system-ninja) { QT_TOOL.ninja.binary = ninja } else { QT_TOOL.ninja.binary = $$shell_quote($$shell_path($$ninjaPath())) @@ -35,7 +35,7 @@ build_pass|!debug_and_release { gn_args += "qtwebengine_target=\"$$system_path($$OUT_PWD/$$getConfigDir()):QtWebEngineCore\"" - !qtConfig(system-gn) { + !qtConfig(webengine-system-gn) { gn_binary = $$system_quote($$system_path($$gnPath())) } diff --git a/src/core/render_widget_host_view_qt.cpp b/src/core/render_widget_host_view_qt.cpp index a12dea6ad..e084de463 100644 --- a/src/core/render_widget_host_view_qt.cpp +++ b/src/core/render_widget_host_view_qt.cpp @@ -73,6 +73,7 @@ #include "ui/events/event.h" #include "ui/events/gesture_detection/gesture_provider_config_helper.h" #include "ui/events/gesture_detection/motion_event.h" +#include "ui/events/keycodes/keyboard_codes.h" #include "ui/gfx/geometry/size_conversions.h" #if defined(USE_AURA) @@ -97,6 +98,9 @@ #include <QVariant> #include <QWheelEvent> #include <QWindow> +#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) +#include <QtGui/private/qinputcontrol_p.h> +#endif #include <QtGui/qaccessible.h> namespace QtWebEngineCore { @@ -184,6 +188,59 @@ static inline bool compareTouchPoints(const QTouchEvent::TouchPoint &lhs, const return lhs.state() < rhs.state(); } +static inline bool isCommonTextEditShortcut(const QKeyEvent *ke) +{ +#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) + return QInputControl::isCommonTextEditShortcut(ke); +#else + if (ke->modifiers() == Qt::NoModifier + || ke->modifiers() == Qt::ShiftModifier + || ke->modifiers() == Qt::KeypadModifier) { + if (ke->key() < Qt::Key_Escape) { + return true; + } else { + switch (ke->key()) { + case Qt::Key_Return: + case Qt::Key_Enter: + case Qt::Key_Delete: + case Qt::Key_Home: + case Qt::Key_End: + case Qt::Key_Backspace: + case Qt::Key_Left: + case Qt::Key_Right: + case Qt::Key_Up: + case Qt::Key_Down: + case Qt::Key_Tab: + return true; + default: + break; + } + } + } else if (ke->matches(QKeySequence::Copy) + || ke->matches(QKeySequence::Paste) + || ke->matches(QKeySequence::Cut) + || ke->matches(QKeySequence::Redo) + || ke->matches(QKeySequence::Undo) + || ke->matches(QKeySequence::MoveToNextWord) + || ke->matches(QKeySequence::MoveToPreviousWord) + || ke->matches(QKeySequence::MoveToStartOfDocument) + || ke->matches(QKeySequence::MoveToEndOfDocument) + || ke->matches(QKeySequence::SelectNextWord) + || ke->matches(QKeySequence::SelectPreviousWord) + || ke->matches(QKeySequence::SelectStartOfLine) + || ke->matches(QKeySequence::SelectEndOfLine) + || ke->matches(QKeySequence::SelectStartOfBlock) + || ke->matches(QKeySequence::SelectEndOfBlock) + || ke->matches(QKeySequence::SelectStartOfDocument) + || ke->matches(QKeySequence::SelectEndOfDocument) + || ke->matches(QKeySequence::SelectAll) + ) { + return true; + } + return false; +#endif +} + static uint32_t s_eventId = 0; class MotionEventQt : public ui::MotionEvent { public: @@ -234,7 +291,7 @@ public: float GetHistoricalTouchMajor(size_t pointer_index, size_t historical_index) const override { return 0; } float GetHistoricalX(size_t pointer_index, size_t historical_index) const override { return 0; } float GetHistoricalY(size_t pointer_index, size_t historical_index) const override { return 0; } - ToolType GetToolType(size_t pointer_index) const override { return ui::MotionEvent::TOOL_TYPE_UNKNOWN; } + ToolType GetToolType(size_t pointer_index) const override { return ui::MotionEvent::TOOL_TYPE_FINGER; } int GetButtonState() const override { return 0; } private: @@ -934,6 +991,41 @@ bool RenderWidgetHostViewQt::forwardEvent(QEvent *event) Q_ASSERT(m_host->GetView()); switch (event->type()) { + case QEvent::ShortcutOverride: { + QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event); + + auto acceptKeyOutOfInputField = [](QKeyEvent *keyEvent) -> bool { +#ifdef Q_OS_MACOS + // Try triggering a registered shortcut + if (QGuiApplicationPrivate::instance()->shortcutMap.tryShortcut(keyEvent)) + 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() && !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(); // Fall through. case QEvent::MouseButtonRelease: @@ -982,6 +1074,10 @@ bool RenderWidgetHostViewQt::forwardEvent(QEvent *event) case QEvent::InputMethodQuery: handleInputMethodQueryEvent(static_cast<QInputMethodQueryEvent*>(event)); break; + case QEvent::HoverLeave: + case QEvent::Leave: + m_host->ForwardMouseEvent(WebEventFactory::toWebMouseEvent(event)); + break; default: return false; } @@ -1127,6 +1223,16 @@ void RenderWidgetHostViewQt::handleKeyEvent(QKeyEvent *ev) } 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(); + m_host->ForwardKeyboardEventWithCommands(webEvent, latency, &commands, nullptr); + return; + } + bool keyDownTextInsertion = webEvent.GetType() == blink::WebInputEvent::kRawKeyDown && webEvent.text[0]; webEvent.skip_in_browser = keyDownTextInsertion; m_host->ForwardKeyboardEvent(webEvent); diff --git a/src/core/render_widget_host_view_qt.h b/src/core/render_widget_host_view_qt.h index c896cf058..1ac32456a 100644 --- a/src/core/render_widget_host_view_qt.h +++ b/src/core/render_widget_host_view_qt.h @@ -278,6 +278,8 @@ private: bool m_wheelAckPending; QList<blink::WebMouseWheelEvent> m_pendingWheelEvents; + + std::string m_editCommand; }; } // namespace QtWebEngineCore diff --git a/src/core/render_widget_host_view_qt_delegate.cpp b/src/core/render_widget_host_view_qt_delegate.cpp deleted file mode 100644 index a86900433..000000000 --- a/src/core/render_widget_host_view_qt_delegate.cpp +++ /dev/null @@ -1,113 +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 "render_widget_host_view_qt_delegate.h" - -#include <QtCore/qvariant.h> -#include <QtGui/qevent.h> - -#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) -#include <QtGui/private/qinputcontrol_p.h> -#endif - -static bool isCommonTextEditShortcut(const QKeyEvent *ke) -{ -#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) - return QInputControl::isCommonTextEditShortcut(ke); -#else - if (ke->modifiers() == Qt::NoModifier - || ke->modifiers() == Qt::ShiftModifier - || ke->modifiers() == Qt::KeypadModifier) { - if (ke->key() < Qt::Key_Escape) { - return true; - } else { - switch (ke->key()) { - case Qt::Key_Return: - case Qt::Key_Enter: - case Qt::Key_Delete: - case Qt::Key_Home: - case Qt::Key_End: - case Qt::Key_Backspace: - case Qt::Key_Left: - case Qt::Key_Right: - case Qt::Key_Up: - case Qt::Key_Down: - case Qt::Key_Tab: - return true; - default: - break; - } - } - } else if (ke->matches(QKeySequence::Copy) - || ke->matches(QKeySequence::Paste) - || ke->matches(QKeySequence::Cut) - || ke->matches(QKeySequence::Redo) - || ke->matches(QKeySequence::Undo) - || ke->matches(QKeySequence::MoveToNextWord) - || ke->matches(QKeySequence::MoveToPreviousWord) - || ke->matches(QKeySequence::MoveToStartOfDocument) - || ke->matches(QKeySequence::MoveToEndOfDocument) - || ke->matches(QKeySequence::SelectNextWord) - || ke->matches(QKeySequence::SelectPreviousWord) - || ke->matches(QKeySequence::SelectStartOfLine) - || ke->matches(QKeySequence::SelectEndOfLine) - || ke->matches(QKeySequence::SelectStartOfBlock) - || ke->matches(QKeySequence::SelectEndOfBlock) - || ke->matches(QKeySequence::SelectStartOfDocument) - || ke->matches(QKeySequence::SelectEndOfDocument) - || ke->matches(QKeySequence::SelectAll) - ) { - return true; - } - return false; -#endif -} - -namespace QtWebEngineCore { - -bool RenderWidgetHostViewQtDelegateClient::handleShortcutOverrideEvent(QKeyEvent *event) -{ - if (inputMethodQuery(Qt::ImEnabled).toBool() && isCommonTextEditShortcut(event)) { - event->accept(); - return true; - } - return false; -} - -} // 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 a126410ed..bcd0f49f7 100644 --- a/src/core/render_widget_host_view_qt_delegate.h +++ b/src/core/render_widget_host_view_qt_delegate.h @@ -48,7 +48,6 @@ QT_BEGIN_NAMESPACE class QCursor; class QEvent; -class QKeyEvent; class QPainter; class QSGLayer; class QSGNode; @@ -79,7 +78,6 @@ public: virtual void windowChanged() = 0; virtual bool forwardEvent(QEvent *) = 0; virtual QVariant inputMethodQuery(Qt::InputMethodQuery query) = 0; - virtual bool handleShortcutOverrideEvent(QKeyEvent *event); }; class QWEBENGINE_EXPORT RenderWidgetHostViewQtDelegate { diff --git a/src/core/renderer/content_renderer_client_qt.cpp b/src/core/renderer/content_renderer_client_qt.cpp index 83c4d719e..5980d7b84 100644 --- a/src/core/renderer/content_renderer_client_qt.cpp +++ b/src/core/renderer/content_renderer_client_qt.cpp @@ -262,11 +262,11 @@ public: return true; case media::EmeInitDataType::CENC: -#if defined(USE_PROPRIETARY_CODECS) +#if BUILDFLAG(USE_PROPRIETARY_CODECS) return true; #else return false; -#endif // defined(USE_PROPRIETARY_CODECS) +#endif // BUILDFLAG(USE_PROPRIETARY_CODECS) case media::EmeInitDataType::UNKNOWN: return false; @@ -277,7 +277,7 @@ public: media::SupportedCodecs GetSupportedCodecs() const override { -#if defined(USE_PROPRIETARY_CODECS) +#if BUILDFLAG(USE_PROPRIETARY_CODECS) return media::EME_CODEC_MP4_ALL | media::EME_CODEC_WEBM_ALL; #else return media::EME_CODEC_WEBM_ALL; @@ -390,10 +390,10 @@ static void AddPepperBasedWidevine(std::vector<std::unique_ptr<media::KeySystemP supported_codecs |= media::EME_CODEC_WEBM_VORBIS; supported_codecs |= media::EME_CODEC_WEBM_VP8; supported_codecs |= media::EME_CODEC_WEBM_VP9; -#if defined(USE_PROPRIETARY_CODECS) +#if BUILDFLAG(USE_PROPRIETARY_CODECS) supported_codecs |= media::EME_CODEC_MP4_AVC1; supported_codecs |= media::EME_CODEC_MP4_AAC; -#endif // defined(USE_PROPRIETARY_CODECS) +#endif // BUILDFLAG(USE_PROPRIETARY_CODECS) using Robustness = cdm::WidevineKeySystemProperties::Robustness; concrete_key_systems->emplace_back(new cdm::WidevineKeySystemProperties( diff --git a/src/core/renderer/web_channel_ipc_transport.cpp b/src/core/renderer/web_channel_ipc_transport.cpp index 8374a8e6b..534ee302d 100644 --- a/src/core/renderer/web_channel_ipc_transport.cpp +++ b/src/core/renderer/web_channel_ipc_transport.cpp @@ -186,7 +186,7 @@ void WebChannelIPCTransport::installWebChannel(uint worldId) void WebChannelIPCTransport::uninstallWebChannel(uint worldId) { - Q_ASSERT(worldId = m_installedWorldId); + Q_ASSERT(worldId == m_installedWorldId); blink::WebView *webView = render_view()->GetWebView(); if (!webView) return; diff --git a/src/core/url_request_qrc_job_qt.cpp b/src/core/url_request_qrc_job_qt.cpp index b4e960921..a2712653d 100644 --- a/src/core/url_request_qrc_job_qt.cpp +++ b/src/core/url_request_qrc_job_qt.cpp @@ -112,7 +112,7 @@ int URLRequestQrcJobQt::ReadRawData(IOBuffer *buf, int bufSize) void URLRequestQrcJobQt::startGetHead() { // Get qrc file path. - QString qrcFilePath = ':' + toQt(request_->url()).path(QUrl::RemovePath | QUrl::RemoveQuery); + QString qrcFilePath = ':' + toQt(request_->url()).path(); m_file.setFileName(qrcFilePath); QFileInfo qrcFileInfo(m_file); // Get qrc file mime type. diff --git a/src/core/web_contents_adapter.cpp b/src/core/web_contents_adapter.cpp index 6576a9c3b..68481dccc 100644 --- a/src/core/web_contents_adapter.cpp +++ b/src/core/web_contents_adapter.cpp @@ -600,6 +600,8 @@ void WebContentsAdapter::load(const QWebEngineHttpRequest &request) } d->webContents->GetController().LoadURLWithParams(params); + // Follow chrome::Navigate and invalidate the URL immediately. + d->webContentsDelegate->NavigationStateChanged(d->webContents.get(), content::INVALIDATE_TYPE_URL); focusIfNecessary(); } @@ -641,7 +643,7 @@ void WebContentsAdapter::save(const QString &filePath, int savePageFormat) QUrl WebContentsAdapter::activeUrl() const { Q_D(const WebContentsAdapter); - return toQt(d->webContents->GetLastCommittedURL()); + return d->webContentsDelegate->url(); } QUrl WebContentsAdapter::requestedUrl() const @@ -676,7 +678,7 @@ QUrl WebContentsAdapter::iconUrl() const QString WebContentsAdapter::pageTitle() const { Q_D(const WebContentsAdapter); - return toQt(d->webContents->GetTitle()); + return d->webContentsDelegate->title(); } QString WebContentsAdapter::selectedText() const @@ -1469,6 +1471,12 @@ void WebContentsAdapter::focusIfNecessary() d->webContents->Focus(); } +bool WebContentsAdapter::isFindTextInProgress() const +{ + Q_D(const WebContentsAdapter); + return d->lastFindRequestId != d->webContentsDelegate->lastReceivedFindReply(); +} + WebContentsAdapterClient::RenderProcessTerminationStatus WebContentsAdapterClient::renderProcessExitStatus(int terminationStatus) { auto status = WebContentsAdapterClient::RenderProcessTerminationStatus(-1); diff --git a/src/core/web_contents_adapter.h b/src/core/web_contents_adapter.h index 67fcbe7af..51fd2891d 100644 --- a/src/core/web_contents_adapter.h +++ b/src/core/web_contents_adapter.h @@ -184,6 +184,7 @@ public: void viewSource(); bool canViewSource(); void focusIfNecessary(); + bool isFindTextInProgress() const; private: diff --git a/src/core/web_contents_delegate_qt.cpp b/src/core/web_contents_delegate_qt.cpp index 54aeac710..25aa9ae04 100644 --- a/src/core/web_contents_delegate_qt.cpp +++ b/src/core/web_contents_delegate_qt.cpp @@ -132,10 +132,21 @@ content::WebContents *WebContentsDelegateQt::OpenURLFromTab(content::WebContents void WebContentsDelegateQt::NavigationStateChanged(content::WebContents* source, content::InvalidateTypes changed_flags) { - if (changed_flags & content::INVALIDATE_TYPE_URL) - m_viewClient->urlChanged(toQt(source->GetVisibleURL())); - if (changed_flags & content::INVALIDATE_TYPE_TITLE) - m_viewClient->titleChanged(toQt(source->GetTitle())); + if (changed_flags & content::INVALIDATE_TYPE_URL) { + QUrl newUrl = toQt(source->GetVisibleURL()); + if (m_url != newUrl) { + m_url = newUrl; + m_viewClient->urlChanged(m_url); + } + } + + if (changed_flags & content::INVALIDATE_TYPE_TITLE) { + QString newTitle = toQt(source->GetTitle()); + if (m_title != newTitle) { + m_title = newTitle; + m_viewClient->titleChanged(m_title); + } + } // NavigationStateChanged gets called with INVALIDATE_TYPE_TAB by AudioStateProvider::Notify, // whenever an audio sound gets played or stopped, this is the only way to actually figure out @@ -147,20 +158,6 @@ void WebContentsDelegateQt::NavigationStateChanged(content::WebContents* source, } } -bool WebContentsDelegateQt::ShouldPreserveAbortedURLs(content::WebContents *source) -{ - Q_UNUSED(source) - - // Allow failed URLs to stick around in the URL bar, but only when the error-page is enabled. - WebEngineSettings *settings = m_viewClient->webEngineSettings(); - bool isErrorPageEnabled = settings->testAttribute(settings->Attribute::ErrorPageEnabled); - - if (isErrorPageEnabled) - return true; - - return false; -} - void WebContentsDelegateQt::AddNewContents(content::WebContents* source, content::WebContents* new_contents, WindowOpenDisposition disposition, const gfx::Rect& initial_pos, bool user_gesture, bool* was_blocked) { Q_UNUSED(source) diff --git a/src/core/web_contents_delegate_qt.h b/src/core/web_contents_delegate_qt.h index 87b7271f6..87704d3c6 100644 --- a/src/core/web_contents_delegate_qt.h +++ b/src/core/web_contents_delegate_qt.h @@ -97,6 +97,9 @@ public: void setLastSearchedString(const QString &s) { m_lastSearchedString = s; } int lastReceivedFindReply() const { return m_lastReceivedFindReply; } + QUrl url() const { return m_url; } + QString title() const { return m_title; } + // WebContentsDelegate overrides content::WebContents *OpenURLFromTab(content::WebContents *source, const content::OpenURLParams ¶ms) override; void NavigationStateChanged(content::WebContents* source, content::InvalidateTypes changed_flags) override; @@ -119,7 +122,6 @@ public: bool IsPopupOrPanel(const content::WebContents *source) const override; void UpdateTargetURL(content::WebContents* source, const GURL& url) override; void RequestToLockMouse(content::WebContents *web_contents, bool user_gesture, bool last_unlocked_by_target) override; - bool ShouldPreserveAbortedURLs(content::WebContents *source) override; void ShowValidationMessage(content::WebContents *web_contents, const gfx::Rect &anchor_in_root_view, const base::string16 &main_text, const base::string16 &sub_text) override; void HideValidationMessage(content::WebContents *web_contents) override; void MoveValidationMessage(content::WebContents *web_contents, const gfx::Rect &anchor_in_root_view) override; @@ -165,6 +167,9 @@ private: QSharedPointer<FilePickerController> m_filePickerController; QUrl m_initialTargetUrl; int m_lastLoadProgress; + + QUrl m_url; + QString m_title; }; } // namespace QtWebEngineCore diff --git a/src/core/web_event_factory.cpp b/src/core/web_event_factory.cpp index 2e0323f6d..4241a11c2 100644 --- a/src/core/web_event_factory.cpp +++ b/src/core/web_event_factory.cpp @@ -1020,12 +1020,14 @@ static ui::DomKey getDomKeyFromQKeyEvent(QKeyEvent *ev) } } -static inline double currentTimeForEvent(const QInputEvent* event) +static inline double currentTimeForEvent(const QEvent *event) { Q_ASSERT(event); - if (event->timestamp()) - return static_cast<double>(event->timestamp()) / 1000; + if (const QInputEvent *inputEvent = static_cast<const QInputEvent *>(event)) { + if (inputEvent->timestamp()) + return static_cast<double>(inputEvent->timestamp()) / 1000; + } static QElapsedTimer timer; if (!timer.isValid()) @@ -1209,6 +1211,7 @@ WebMouseEvent WebEventFactory::toWebMouseEvent(QMouseEvent *ev, double dpiScale) webKitEvent.button = mouseButtonForEvent<QMouseEvent>(ev); webKitEvent.click_count = 0; + webKitEvent.pointer_type = WebPointerProperties::PointerType::kMouse; return webKitEvent; } @@ -1223,6 +1226,7 @@ WebMouseEvent WebEventFactory::toWebMouseEvent(QHoverEvent *ev, double dpiScale) webKitEvent.SetPositionInWidget(ev->pos().x() / dpiScale, ev->pos().y() / dpiScale); webKitEvent.movement_x = ev->pos().x() - ev->oldPos().x(); webKitEvent.movement_y = ev->pos().y() - ev->oldPos().y(); + webKitEvent.pointer_type = WebPointerProperties::PointerType::kMouse; return webKitEvent; } @@ -1246,7 +1250,16 @@ WebMouseEvent WebEventFactory::toWebMouseEvent(QTabletEvent *ev, double dpiScale webKitEvent.button = mouseButtonForEvent<QTabletEvent>(ev); webKitEvent.click_count = 0; + return webKitEvent; +} + +WebMouseEvent WebEventFactory::toWebMouseEvent(QEvent *ev) +{ + Q_ASSERT(ev->type() == QEvent::Leave || ev->type() == QEvent::HoverLeave); + WebMouseEvent webKitEvent; + webKitEvent.SetTimeStampSeconds(currentTimeForEvent(ev)); + webKitEvent.SetType(WebInputEvent::kMouseLeave); return webKitEvent; } @@ -1370,3 +1383,83 @@ content::NativeWebKeyboardEvent WebEventFactory::toWebKeyboardEvent(QKeyEvent *e return webKitEvent; } + +bool WebEventFactory::getEditCommand(QKeyEvent *event, std::string *editCommand) +{ + // Assign Qt standard key bindings to blink editor commands. Editor command names + // come from chromium/third_party/WebKit/Source/editing/commands/EditorCommandNames.h + static struct { + QKeySequence::StandardKey standardKey; + std::string name; + } editCommands[] = { + { QKeySequence::Delete, "Delete" }, + { QKeySequence::Cut, "Cut" }, + { QKeySequence::Copy, "Copy" }, + { QKeySequence::Paste, "Paste" }, + { QKeySequence::Undo, "Undo" }, + { QKeySequence::Redo, "Redo" }, + { QKeySequence::SelectAll, "SelectAll" }, + { QKeySequence::Bold, "Bold" }, + { QKeySequence::Italic, "Italic" }, + { QKeySequence::Underline, "Underline" }, + + { QKeySequence::MoveToNextChar, "MoveRight" }, + { QKeySequence::MoveToPreviousChar, "MoveLeft" }, + { QKeySequence::MoveToNextWord, "MoveWordForward" }, + { QKeySequence::MoveToPreviousWord, "MoveWordBackward" }, + { QKeySequence::MoveToNextLine, "MoveDown" }, + { QKeySequence::MoveToPreviousLine, "MoveUp" }, + { QKeySequence::MoveToNextPage, "MovePageDown" }, + { QKeySequence::MoveToPreviousPage, "MovePageUp" }, + { QKeySequence::MoveToStartOfLine, "MoveToBeginningOfLine" }, + { QKeySequence::MoveToEndOfLine, "MoveToEndOfLine" }, + { QKeySequence::MoveToStartOfBlock, "MoveToBeginningOfParagraph" }, + { QKeySequence::MoveToEndOfBlock, "MoveToEndOfParagraph" }, + { QKeySequence::MoveToStartOfDocument, "MoveToBeginningOfDocument" }, + { QKeySequence::MoveToEndOfDocument, "MoveToEndOfDocument" }, + + { QKeySequence::SelectNextChar, "MoveRightAndModifySelection" }, + { QKeySequence::SelectPreviousChar, "MoveLeftAndModifySelection" }, + { QKeySequence::SelectNextWord, "MoveWordForwardAndModifySelection" }, + { QKeySequence::SelectPreviousWord, "MoveWordBackwardAndModifySelection" }, + { QKeySequence::SelectNextLine, "MoveDownAndModifySelection" }, + { QKeySequence::SelectPreviousLine, "MoveUpAndModifySelection" }, + { QKeySequence::SelectNextPage, "MovePageDownAndModifySelection" }, + { QKeySequence::SelectPreviousPage, "MovePageUpAndModifySelection" }, + { QKeySequence::SelectStartOfLine, "MoveToBeginningOfLineAndModifySelection" }, + { QKeySequence::SelectEndOfLine, "MoveToEndOfLineAndModifySelection" }, + { QKeySequence::SelectStartOfBlock, "MoveToBeginningOfParagraphAndModifySelection" }, + { QKeySequence::SelectEndOfBlock, "MoveToEndOfParagraphAndModifySelection" }, + { QKeySequence::SelectStartOfDocument, "MoveToBeginningOfDocumentAndModifySelection" }, + { QKeySequence::SelectEndOfDocument, "MoveToEndOfDocumentAndModifySelection" }, + + { QKeySequence::DeleteStartOfWord, "DeleteWordBackward" }, + { QKeySequence::DeleteEndOfWord, "DeleteWordForward" }, + { QKeySequence::DeleteEndOfLine, "DeleteToEndOfLine" }, + { QKeySequence::Deselect, "Unselect" }, + { QKeySequence::Backspace, "BackwardDelete" }, + + { QKeySequence::UnknownKey, "" } + }; + + for (int i = 0; editCommands[i].standardKey != QKeySequence::UnknownKey; ++i) { + if (event == editCommands[i].standardKey) { + *editCommand = editCommands[i].name; + return true; + } + } + +#ifdef Q_OS_MACOS + Qt::KeyboardModifier cmdKey = qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta) ? + Qt::MetaModifier : + Qt::ControlModifier; + if ((event->modifiers() & ~Qt::ShiftModifier) == cmdKey) { + if (event->key() == Qt::Key_Backspace) { + *editCommand = "DeleteToBeginningOfLine"; + return true; + } + } +#endif + + return false; +} diff --git a/src/core/web_event_factory.h b/src/core/web_event_factory.h index ca0f6035f..442f04054 100644 --- a/src/core/web_event_factory.h +++ b/src/core/web_event_factory.h @@ -50,6 +50,7 @@ #include <QtGlobal> QT_BEGIN_NAMESPACE +class QEvent; class QHoverEvent; class QKeyEvent; class QMouseEvent; @@ -66,12 +67,14 @@ public: static blink::WebMouseEvent toWebMouseEvent(QMouseEvent*, double dpiScale); static blink::WebMouseEvent toWebMouseEvent(QHoverEvent*, double dpiScale); static blink::WebMouseEvent toWebMouseEvent(QTabletEvent*, double dpiScale); + static blink::WebMouseEvent toWebMouseEvent(QEvent *); #ifndef QT_NO_GESTURES static blink::WebGestureEvent toWebGestureEvent(QNativeGestureEvent *, double dpiScale); #endif static blink::WebMouseWheelEvent toWebWheelEvent(QWheelEvent*, double dpiScale); static bool coalesceWebWheelEvent(blink::WebMouseWheelEvent &, QWheelEvent*, double dpiScale); static content::NativeWebKeyboardEvent toWebKeyboardEvent(QKeyEvent*); + static bool getEditCommand(QKeyEvent *event, std::string *editCommand); }; diff --git a/src/src.pro b/src/src.pro index 76d342c8d..d675f1f13 100644 --- a/src/src.pro +++ b/src/src.pro @@ -20,20 +20,20 @@ SUBDIRS += buildtools \ plugins -qtConfig(spellchecker):!qtConfig(native-spellchecker):!cross_compile { +qtConfig(webengine-spellchecker):!qtConfig(webengine-native-spellchecker):!cross_compile { SUBDIRS += qwebengine_convert_dict qwebengine_convert_dict.subdir = tools/qwebengine_convert_dict qwebengine_convert_dict.depends = core } -qtConfig(testsupport) { +qtConfig(webengine-testsupport) { webengine_testsupport_plugin.subdir = webengine/plugin/testsupport webengine_testsupport_plugin.target = sub-webengine-testsupport-plugin webengine_testsupport_plugin.depends = webengine SUBDIRS += webengine_testsupport_plugin } -qtConfig(ui-delegates) { +qtConfig(webengine-ui-delegates) { SUBDIRS += webengine/ui \ webengine/ui2 } diff --git a/src/webengine/api/qquickwebengineview.cpp b/src/webengine/api/qquickwebengineview.cpp index e11147760..0636d8471 100644 --- a/src/webengine/api/qquickwebengineview.cpp +++ b/src/webengine/api/qquickwebengineview.cpp @@ -95,27 +95,6 @@ QT_BEGIN_NAMESPACE using namespace QtWebEngineCore; -QQuickWebEngineView::WebAction editorActionForKeyEvent(QKeyEvent* event) -{ - static struct { - QKeySequence::StandardKey standardKey; - QQuickWebEngineView::WebAction action; - } editorActions[] = { - { QKeySequence::Cut, QQuickWebEngineView::Cut }, - { QKeySequence::Copy, QQuickWebEngineView::Copy }, - { QKeySequence::Paste, QQuickWebEngineView::Paste }, - { QKeySequence::Undo, QQuickWebEngineView::Undo }, - { QKeySequence::Redo, QQuickWebEngineView::Redo }, - { QKeySequence::SelectAll, QQuickWebEngineView::SelectAll }, - { QKeySequence::UnknownKey, QQuickWebEngineView::NoWebAction } - }; - for (int i = 0; editorActions[i].standardKey != QKeySequence::UnknownKey; ++i) - if (event == editorActions[i].standardKey) - return editorActions[i].action; - - return QQuickWebEngineView::NoWebAction; -} - #ifndef QT_NO_ACCESSIBILITY static QAccessibleInterface *webAccessibleFactory(const QString &, QObject *object) { @@ -360,7 +339,7 @@ void QQuickWebEngineViewPrivate::navigationRequested(int navigationType, const Q Q_EMIT q->navigationRequested(&navigationRequest); navigationRequestAction = navigationRequest.action(); - if ((navigationRequestAction == WebContentsAdapterClient::AcceptRequest) && adapter) + if ((navigationRequestAction == WebContentsAdapterClient::AcceptRequest) && adapter && adapter->isFindTextInProgress()) adapter->stopFinding(); } @@ -579,18 +558,6 @@ void QQuickWebEngineViewPrivate::focusContainer() void QQuickWebEngineViewPrivate::unhandledKeyEvent(QKeyEvent *event) { Q_Q(QQuickWebEngineView); -#ifdef Q_OS_OSX - if (event->type() == QEvent::KeyPress) { - QQuickWebEngineView::WebAction action = editorActionForKeyEvent(event); - if (action != QQuickWebEngineView::NoWebAction) { - // Try triggering a registered short-cut - if (QGuiApplicationPrivate::instance()->shortcutMap.tryShortcut(event)) - return; - q->triggerWebAction(action); - return; - } - } -#endif if (q->parentItem()) QCoreApplication::sendEvent(q->parentItem(), event); } diff --git a/src/webengine/render_widget_host_view_qt_delegate_quick.cpp b/src/webengine/render_widget_host_view_qt_delegate_quick.cpp index cde742c39..0a31811d9 100644 --- a/src/webengine/render_widget_host_view_qt_delegate_quick.cpp +++ b/src/webengine/render_widget_host_view_qt_delegate_quick.cpp @@ -225,7 +225,7 @@ void RenderWidgetHostViewQtDelegateQuick::inputMethodStateChanged(bool editorVis bool RenderWidgetHostViewQtDelegateQuick::event(QEvent *event) { if (event->type() == QEvent::ShortcutOverride) - return m_client->handleShortcutOverrideEvent(static_cast<QKeyEvent *>(event)); + return m_client->forwardEvent(event); #ifndef QT_NO_GESTURES if (event->type() == QEvent::NativeGesture) @@ -316,6 +316,11 @@ void RenderWidgetHostViewQtDelegateQuick::hoverMoveEvent(QHoverEvent *event) m_client->forwardEvent(event); } +void RenderWidgetHostViewQtDelegateQuick::hoverLeaveEvent(QHoverEvent *event) +{ + m_client->forwardEvent(event); +} + QVariant RenderWidgetHostViewQtDelegateQuick::inputMethodQuery(Qt::InputMethodQuery query) const { return m_client->inputMethodQuery(query); diff --git a/src/webengine/render_widget_host_view_qt_delegate_quick.h b/src/webengine/render_widget_host_view_qt_delegate_quick.h index cbcb58c11..a5101d070 100644 --- a/src/webengine/render_widget_host_view_qt_delegate_quick.h +++ b/src/webengine/render_widget_host_view_qt_delegate_quick.h @@ -90,6 +90,7 @@ protected: void wheelEvent(QWheelEvent *event) override; void touchEvent(QTouchEvent *event) override; void hoverMoveEvent(QHoverEvent *event) override; + void hoverLeaveEvent(QHoverEvent *event) override; QVariant inputMethodQuery(Qt::InputMethodQuery query) const override; void inputMethodEvent(QInputMethodEvent *event) override; void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override; diff --git a/src/webengine/ui_delegates_manager.cpp b/src/webengine/ui_delegates_manager.cpp index 43e6e8817..fb23f5db7 100644 --- a/src/webengine/ui_delegates_manager.cpp +++ b/src/webengine/ui_delegates_manager.cpp @@ -257,7 +257,7 @@ QObject *UIDelegatesManager::addMenu(QObject *parentMenu, const QString &title, if (!title.isEmpty()) QQmlProperty(menu, QStringLiteral("title")).write(title); if (!pos.isNull()) - QQmlProperty(menu, QStringLiteral("pos")).write(pos); + menu->setProperty("pos", pos); menu->setParent(parentMenu); @@ -496,9 +496,38 @@ void UIDelegatesManager::showFilePicker(QSharedPointer<FilePickerController> con QMetaObject::invokeMethod(filePicker, "open"); } +class TemporaryCursorMove +{ +public: + TemporaryCursorMove(const QQuickItem *item, const QPoint &pos) + { + if (pos.isNull() || !item->contains(pos)) + return; + const QPoint oldPos = QCursor::pos(); + const QPoint globalPos = item->mapToGlobal(QPointF(pos)).toPoint(); + if (oldPos == globalPos) + return; + m_oldCursorPos = oldPos; + QCursor::setPos(globalPos); + } + + ~TemporaryCursorMove() + { + if (!m_oldCursorPos.isNull()) + QCursor::setPos(m_oldCursorPos); + } + +private: + QPoint m_oldCursorPos; +}; + void UIDelegatesManager::showMenu(QObject *menu) { - QMetaObject::invokeMethod(menu, "popup"); + // QtQuick.Controls.Menu.popup() always shows the menu under the mouse cursor, i.e. the menu's + // position we set above is ignored. Work around the problem by moving the mouse cursor + // temporarily to the right position. + TemporaryCursorMove tcm(m_view, menu->property("pos").toPoint()); + QMetaObject::invokeMethod(menu, "popup"); } void UIDelegatesManager::showMessageBubble(const QRect &anchor, const QString &mainText, const QString &subText) diff --git a/src/webengine/webengine.pro b/src/webengine/webengine.pro index 24fa2d9d8..58e1263a7 100644 --- a/src/webengine/webengine.pro +++ b/src/webengine/webengine.pro @@ -58,7 +58,7 @@ HEADERS = \ render_widget_host_view_qt_delegate_quickwindow.h \ ui_delegates_manager.h -qtConfig(testsupport) { +qtConfig(webengine-testsupport) { QT += testlib SOURCES += api/qquickwebenginetestsupport.cpp @@ -67,11 +67,11 @@ qtConfig(testsupport) { DEFINES += ENABLE_QML_TESTSUPPORT_API } -qtConfig(spellchecker) { +qtConfig(webengine-spellchecker) { DEFINES += ENABLE_SPELLCHECK } -qtConfig(printing-and-pdf) { +qtConfig(webengine-printing-and-pdf) { DEFINES += ENABLE_PDF } diff --git a/src/webenginewidgets/api/qwebenginepage.cpp b/src/webenginewidgets/api/qwebenginepage.cpp index dc525db93..4a892103d 100644 --- a/src/webenginewidgets/api/qwebenginepage.cpp +++ b/src/webenginewidgets/api/qwebenginepage.cpp @@ -376,19 +376,6 @@ void QWebEnginePagePrivate::focusContainer() void QWebEnginePagePrivate::unhandledKeyEvent(QKeyEvent *event) { -#ifdef Q_OS_OSX - Q_Q(QWebEnginePage); - if (event->type() == QEvent::KeyPress) { - QWebEnginePage::WebAction action = editorActionForKeyEvent(event); - if (action != QWebEnginePage::NoWebAction) { - // Try triggering a registered short-cut - if (QGuiApplicationPrivate::instance()->shortcutMap.tryShortcut(event)) - return; - q->triggerAction(action); - return; - } - } -#endif if (view && view->parentWidget()) QGuiApplication::sendEvent(view->parentWidget(), event); } @@ -1521,7 +1508,7 @@ void QWebEnginePagePrivate::navigationRequested(int navigationType, const QUrl & { Q_Q(QWebEnginePage); bool accepted = q->acceptNavigationRequest(url, static_cast<QWebEnginePage::NavigationType>(navigationType), isMainFrame); - if (accepted && adapter) + if (accepted && adapter && adapter->isFindTextInProgress()) adapter->stopFinding(); navigationRequestAction = accepted ? WebContentsAdapterClient::AcceptRequest : WebContentsAdapterClient::IgnoreRequest; } diff --git a/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc b/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc index 47370a63c..eb91d576d 100644 --- a/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc +++ b/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc @@ -550,6 +550,9 @@ This signal is emitted whenever the selection changes, either interactively or programmatically. For example, by calling triggerAction() with a selection action. + \note When using the mouse to select text by left-clicking and dragging, the signal will be + emitted for each new character selected, and not upon releasing the left mouse button. + \sa selectedText() */ diff --git a/src/webenginewidgets/doc/src/qwebenginesettings_lgpl.qdoc b/src/webenginewidgets/doc/src/qwebenginesettings_lgpl.qdoc index 970a4e4c3..cde26f66b 100644 --- a/src/webenginewidgets/doc/src/qwebenginesettings_lgpl.qdoc +++ b/src/webenginewidgets/doc/src/qwebenginesettings_lgpl.qdoc @@ -163,7 +163,8 @@ origins to access Geolocation again. Disabled by default. (Added in Qt 5.9) \value AllowWindowActivationFromJavaScript - Allows the window.focus() method in JavaScript. Disallowed by default. + Allows activating windows by using the window.focus() JavaScript + method. Disabled by default. (Added in Qt 5.10) \value ShowScrollBars Shows scroll bars. diff --git a/src/webenginewidgets/doc/src/qwebengineview_lgpl.qdoc b/src/webenginewidgets/doc/src/qwebengineview_lgpl.qdoc index 34a61ded3..27ee96c5e 100644 --- a/src/webenginewidgets/doc/src/qwebengineview_lgpl.qdoc +++ b/src/webenginewidgets/doc/src/qwebengineview_lgpl.qdoc @@ -366,6 +366,9 @@ This signal is emitted whenever the selection changes. + \note When using the mouse to select text by left-clicking and dragging, the signal will be + emitted for each new character selected, and not upon releasing the left mouse button. + \sa selectedText() */ diff --git a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp index 69e1c3038..8dd5c158b 100644 --- a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp +++ b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp @@ -67,7 +67,8 @@ protected: bool event(QEvent *event) override { if (event->type() == QEvent::ShortcutOverride) - return m_client->handleShortcutOverrideEvent(static_cast<QKeyEvent *>(event)); + return m_client->forwardEvent(event); + return QQuickItem::event(event); } void focusInEvent(QFocusEvent *event) override @@ -448,10 +449,6 @@ bool RenderWidgetHostViewQtDelegateWidget::event(QEvent *event) case QEvent::FocusOut: // We forward focus events later, once they have made it to the m_rootItem. return QQuickWidget::event(event); - case QEvent::ShortcutOverride: - if (m_client->handleShortcutOverrideEvent(static_cast<QKeyEvent *>(event))) - return true; - break; case QEvent::DragEnter: case QEvent::DragLeave: case QEvent::DragMove: diff --git a/src/webenginewidgets/webenginewidgets.pro b/src/webenginewidgets/webenginewidgets.pro index 958dec07b..37cb7a1f0 100644 --- a/src/webenginewidgets/webenginewidgets.pro +++ b/src/webenginewidgets/webenginewidgets.pro @@ -46,17 +46,17 @@ HEADERS = \ api/qwebengineview_p.h \ render_widget_host_view_qt_delegate_widget.h -qtConfig(ui-delegates) { +qtConfig(webengine-ui-delegates) { SOURCES += ui/messagebubblewidget.cpp HEADERS += ui/messagebubblewidget_p.h DEFINES += QT_UI_DELEGATES } -qtConfig(spellchecker) { +qtConfig(webengine-spellchecker) { DEFINES += ENABLE_SPELLCHECK } -qtConfig(printing-and-pdf) { +qtConfig(webengine-printing-and-pdf) { DEFINES += ENABLE_PRINTING DEFINES += ENABLE_PDF QT += printsupport |