diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2022-05-09 12:04:12 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2022-06-09 18:58:54 +0200 |
commit | 5d1ef38f9f6815807596d0606cf7ed06b7930aac (patch) | |
tree | 441c2b27eb9d169d58cb94a30ac424ebb6b42b65 | |
parent | 3f5b5213d42376470274f0e3aaa51731f0d2552a (diff) |
Create a RWHV delegate in core
This is adapting the Quick code for shared use with widgets,
and allows us to use it from QWebEnginePage.
Pick-to: 6.4
Fixes: QTBUG-96377
Change-Id: I3f09c1a949eff86d80fbe6c513dc66e3f9f2f611
Reviewed-by: Michal Klocek <michal.klocek@qt.io>
27 files changed, 1201 insertions, 1181 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index e9951d187..18078ba5a 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -160,6 +160,7 @@ foreach(arch ${archs}) render_widget_host_view_qt.cpp render_widget_host_view_qt.h render_widget_host_view_qt_delegate.h render_widget_host_view_qt_delegate_client.cpp render_widget_host_view_qt_delegate_client.h + render_widget_host_view_qt_delegate_item.cpp render_widget_host_view_qt_delegate_item.h renderer/content_renderer_client_qt.cpp renderer/content_renderer_client_qt.h renderer/content_settings_observer_qt.cpp renderer/content_settings_observer_qt.h renderer/render_configuration.cpp renderer/render_configuration.h diff --git a/src/core/api/qwebenginepage.cpp b/src/core/api/qwebenginepage.cpp index 0b3cba785..a893d5a80 100644 --- a/src/core/api/qwebenginepage.cpp +++ b/src/core/api/qwebenginepage.cpp @@ -67,6 +67,7 @@ #include "render_view_context_menu_qt.h" #include "render_widget_host_view_qt_delegate.h" #include "render_widget_host_view_qt_delegate_client.h" +#include "render_widget_host_view_qt_delegate_item.h" #include "web_contents_adapter.h" #include <QAction> @@ -84,51 +85,6 @@ QT_BEGIN_NAMESPACE using namespace QtWebEngineCore; -// add temporary dummy code to cover the case when page is loading and there is no view -class DummyDelegate : public QObject, public QtWebEngineCore::RenderWidgetHostViewQtDelegate -{ -public: - DummyDelegate(RenderWidgetHostViewQtDelegateClient *client) : m_delegateClient(client) {}; - ~DummyDelegate() = default; - void initAsPopup(const QRect &) override { Q_UNREACHABLE(); } - QRectF viewGeometry() const override { return QRectF(m_pos, m_size); } - void setKeyboardFocus() override { } - bool hasKeyboardFocus() override { return false; } - void lockMouse() override { Q_UNREACHABLE(); } - void unlockMouse() override { Q_UNREACHABLE(); } - void show() override { m_delegateClient->notifyShown(); } - void hide() override { m_delegateClient->notifyHidden(); } - bool isVisible() const override { Q_UNREACHABLE(); } - QWindow *window() const override { return nullptr; } - void updateCursor(const QCursor &cursor) override - { - Q_UNUSED(cursor); - /*setCursor(cursor);*/ - } - void resize(int width, int height) override - { - m_size = QSize(width, height); - m_delegateClient->visualPropertiesChanged(); - } - void move(const QPoint &) override { Q_UNREACHABLE(); } - void inputMethodStateChanged(bool, bool) override { } - void setInputMethodHints(Qt::InputMethodHints) override { } - void setClearColor(const QColor &) override { } - void adapterClientChanged(WebContentsAdapterClient *) override { } - bool copySurface(const QRect &, const QSize &, QImage &) - { - Q_UNREACHABLE(); - return false; - } - QRect windowGeometry() const override { return QRect(m_pos, m_size); } - bool forwardEvent(QEvent *ev) { return m_delegateClient->forwardEvent(ev); } - -private: - RenderWidgetHostViewQtDelegateClient *m_delegateClient; - QPoint m_pos; - QSize m_size; -}; - static QWebEnginePage::WebWindowType toWindowType(WebContentsAdapterClient::WindowOpenDisposition disposition) { switch (disposition) { @@ -202,6 +158,14 @@ QWebEnginePagePrivate::~QWebEnginePagePrivate() RenderWidgetHostViewQtDelegate *QWebEnginePagePrivate::CreateRenderWidgetHostViewQtDelegate(RenderWidgetHostViewQtDelegateClient *client) { + item = view + ? (QtWebEngineCore::RenderWidgetHostViewQtDelegateItem *)view->CreateRenderWidgetHostViewQtDelegate(client) + : new QtWebEngineCore::RenderWidgetHostViewQtDelegateItem(client, false); + return item; +} + +RenderWidgetHostViewQtDelegate *QWebEnginePagePrivate::CreateRenderWidgetHostViewQtDelegateForPopup(RenderWidgetHostViewQtDelegateClient *client) +{ // Set the QWebEngineView as the parent for a popup delegate, so that the new popup window // responds properly to clicks in case the QWebEngineView is inside a modal QDialog. Setting the // parent essentially notifies the OS that the popup window is part of the modal session, and @@ -209,7 +173,9 @@ RenderWidgetHostViewQtDelegate *QWebEnginePagePrivate::CreateRenderWidgetHostVie // The new delegate will not be deleted by the parent view though, because we unset the parent // when the parent is destroyed. The delegate will be destroyed by Chromium when the popup is // dismissed. - return view ? view->CreateRenderWidgetHostViewQtDelegate(client) : new DummyDelegate(client); + return view + ? view->CreateRenderWidgetHostViewQtDelegateForPopup(client) + : new QtWebEngineCore::RenderWidgetHostViewQtDelegateItem(client, true); } void QWebEnginePagePrivate::initializationFinished() diff --git a/src/core/api/qwebenginepage_p.h b/src/core/api/qwebenginepage_p.h index 785930127..2b76795b5 100644 --- a/src/core/api/qwebenginepage_p.h +++ b/src/core/api/qwebenginepage_p.h @@ -62,11 +62,12 @@ namespace QtWebEngineCore { class RenderWidgetHostViewQtDelegate; -class RenderWidgetHostViewQtDelegateWidget; class RenderWidgetHostViewQtDelegateClient; +class RenderWidgetHostViewQtDelegateItem; class TouchHandleDrawableDelegate; class TouchSelectionMenuController; class WebContentsAdapter; +class WidgetDelegate; } QT_BEGIN_NAMESPACE @@ -94,6 +95,8 @@ public: virtual void setToolTip(const QString &toolTipText) = 0; virtual QtWebEngineCore::RenderWidgetHostViewQtDelegate *CreateRenderWidgetHostViewQtDelegate( QtWebEngineCore::RenderWidgetHostViewQtDelegateClient *client) = 0; + virtual QtWebEngineCore::RenderWidgetHostViewQtDelegate *CreateRenderWidgetHostViewQtDelegateForPopup( + QtWebEngineCore::RenderWidgetHostViewQtDelegateClient *client) = 0; virtual QWebEngineContextMenuRequest *lastContextMenuRequest() const = 0; virtual QWebEnginePage *createPageForWindow(QWebEnginePage::WebWindowType type) = 0; virtual bool isEnabled() const = 0; @@ -118,7 +121,7 @@ public: ~QWebEnginePagePrivate(); QtWebEngineCore::RenderWidgetHostViewQtDelegate* CreateRenderWidgetHostViewQtDelegate(QtWebEngineCore::RenderWidgetHostViewQtDelegateClient *client) override; - QtWebEngineCore::RenderWidgetHostViewQtDelegate* CreateRenderWidgetHostViewQtDelegateForPopup(QtWebEngineCore::RenderWidgetHostViewQtDelegateClient *client) override { return CreateRenderWidgetHostViewQtDelegate(client); } + QtWebEngineCore::RenderWidgetHostViewQtDelegate* CreateRenderWidgetHostViewQtDelegateForPopup(QtWebEngineCore::RenderWidgetHostViewQtDelegateClient *client) override; void initializationFinished() override; void lifecycleStateChanged(LifecycleState state) override; void recommendedStateChanged(LifecycleState state) override; @@ -227,7 +230,8 @@ public: bool defaultAudioMuted; qreal defaultZoomFactor; QTimer wasShownTimer; - QtWebEngineCore::RenderWidgetHostViewQtDelegateWidget *widget = nullptr; + QtWebEngineCore::WidgetDelegate *widget = nullptr; + QtWebEngineCore::RenderWidgetHostViewQtDelegateItem *item = nullptr; #if QT_CONFIG(webengine_printing_and_pdf) QPrinter *currentPrinter = nullptr; #endif diff --git a/src/core/render_widget_host_view_qt.cpp b/src/core/render_widget_host_view_qt.cpp index 572468bc8..d15381d66 100644 --- a/src/core/render_widget_host_view_qt.cpp +++ b/src/core/render_widget_host_view_qt.cpp @@ -894,7 +894,7 @@ bool RenderWidgetHostViewQt::isPopup() const bool RenderWidgetHostViewQt::updateScreenInfo() { display::ScreenInfo oldScreenInfo = m_screenInfo; - QScreen *screen = m_delegate->window() ? m_delegate->window()->screen() : nullptr; + QScreen *screen = m_delegate->Window() ? m_delegate->Window()->screen() : nullptr; m_screenInfo = screenInfoFromQScreen(screen); return (m_screenInfo != oldScreenInfo); diff --git a/src/core/render_widget_host_view_qt_delegate.h b/src/core/render_widget_host_view_qt_delegate.h index 1df1322c7..66a9d7161 100644 --- a/src/core/render_widget_host_view_qt_delegate.h +++ b/src/core/render_widget_host_view_qt_delegate.h @@ -78,7 +78,7 @@ public: virtual void show() = 0; virtual void hide() = 0; virtual bool isVisible() const = 0; - virtual QWindow* window() const = 0; + virtual QWindow *Window() const = 0; virtual void updateCursor(const QCursor &) = 0; virtual void resize(int width, int height) = 0; virtual void move(const QPoint &) = 0; diff --git a/src/webenginequick/render_widget_host_view_qt_delegate_quick.cpp b/src/core/render_widget_host_view_qt_delegate_item.cpp index 93311d992..75ed57271 100644 --- a/src/webenginequick/render_widget_host_view_qt_delegate_quick.cpp +++ b/src/core/render_widget_host_view_qt_delegate_item.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2022 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtWebEngine module of the Qt Toolkit. @@ -37,22 +37,18 @@ ** ****************************************************************************/ -#include "render_widget_host_view_qt_delegate_quick.h" +#include "render_widget_host_view_qt_delegate_item.h" #include "render_widget_host_view_qt_delegate_client.h" -#include "qquickwebengineview_p.h" -#include "qquickwebengineview_p_p.h" - -#include <QtCore/qvariant.h> -#include <QtGui/qguiapplication.h> -#include <QtGui/qwindow.h> -#include <QtQuick/qquickwindow.h> -#include <QtQuick/qsgimagenode.h> +#include <QGuiApplication> +#include <QMouseEvent> +#include <QSGImageNode> +#include <QWindow> namespace QtWebEngineCore { -RenderWidgetHostViewQtDelegateQuick::RenderWidgetHostViewQtDelegateQuick(RenderWidgetHostViewQtDelegateClient *client, bool isPopup) +RenderWidgetHostViewQtDelegateItem::RenderWidgetHostViewQtDelegateItem(RenderWidgetHostViewQtDelegateClient *client, bool isPopup) : m_client(client) , m_isPopup(isPopup) { @@ -67,22 +63,23 @@ RenderWidgetHostViewQtDelegateQuick::RenderWidgetHostViewQtDelegateQuick(RenderW bind(client->compositorId()); } -RenderWidgetHostViewQtDelegateQuick::~RenderWidgetHostViewQtDelegateQuick() +RenderWidgetHostViewQtDelegateItem::~RenderWidgetHostViewQtDelegateItem() { - QQuickWebEngineViewPrivate::bindViewAndWidget(nullptr, this); + if (m_widgetDelegate) { + m_widgetDelegate->Unbind(); + m_widgetDelegate->Destroy(); + } } -void RenderWidgetHostViewQtDelegateQuick::initAsPopup(const QRect &screenRect) +void RenderWidgetHostViewQtDelegateItem::initAsPopup(const QRect &screenRect) { - //note this is called when there is no windowing system - //otherwsie see RenderWidgetHostViewQtDelegateQuickWindow - Q_ASSERT(m_isPopup && parentItem()); - setPosition(screenRect.topLeft()); + Q_ASSERT(m_isPopup); setSize(screenRect.size()); - setVisible(true); + if (m_widgetDelegate) + m_widgetDelegate->InitAsPopup(screenRect); } -QRectF RenderWidgetHostViewQtDelegateQuick::viewGeometry() const +QRectF RenderWidgetHostViewQtDelegateItem::viewGeometry() const { // Transform the entire rect to find the correct top left corner. const QPointF p1 = mapToGlobal(mapFromScene(QPointF(0, 0))); @@ -93,89 +90,138 @@ QRectF RenderWidgetHostViewQtDelegateQuick::viewGeometry() const return geometry; } -QRect RenderWidgetHostViewQtDelegateQuick::windowGeometry() const +QRect RenderWidgetHostViewQtDelegateItem::windowGeometry() const { - if (!window()) + if (!Window()) return QRect(); - return window()->frameGeometry(); + return Window()->frameGeometry(); } -void RenderWidgetHostViewQtDelegateQuick::setKeyboardFocus() +void RenderWidgetHostViewQtDelegateItem::setKeyboardFocus() { setFocus(true); } -bool RenderWidgetHostViewQtDelegateQuick::hasKeyboardFocus() +bool RenderWidgetHostViewQtDelegateItem::hasKeyboardFocus() { return hasActiveFocus(); } -void RenderWidgetHostViewQtDelegateQuick::lockMouse() +void RenderWidgetHostViewQtDelegateItem::lockMouse() { grabMouse(); } -void RenderWidgetHostViewQtDelegateQuick::unlockMouse() +void RenderWidgetHostViewQtDelegateItem::unlockMouse() { ungrabMouse(); } -void RenderWidgetHostViewQtDelegateQuick::show() +void RenderWidgetHostViewQtDelegateItem::show() { - setVisible(true); - m_client->notifyShown(); + if (isVisible()) + m_client->notifyShown(); + else + setVisible(true); } -void RenderWidgetHostViewQtDelegateQuick::hide() +void RenderWidgetHostViewQtDelegateItem::hide() { - setVisible(false); - m_client->notifyHidden(); + if (isVisible()) + setVisible(false); + else + m_client->notifyHidden(); } -bool RenderWidgetHostViewQtDelegateQuick::isVisible() const +bool RenderWidgetHostViewQtDelegateItem::isVisible() const { return QQuickItem::isVisible(); } -QWindow* RenderWidgetHostViewQtDelegateQuick::window() const +QWindow *RenderWidgetHostViewQtDelegateItem::Window() const { + if (m_widgetDelegate) { + if (auto *window = m_widgetDelegate->Window()) + return window; + } return QQuickItem::window(); } -void RenderWidgetHostViewQtDelegateQuick::readyToSwap() +void RenderWidgetHostViewQtDelegateItem::readyToSwap() { // Call update() on UI thread. QMetaObject::invokeMethod(this, &QQuickItem::update, Qt::QueuedConnection); } -void RenderWidgetHostViewQtDelegateQuick::updateCursor(const QCursor &cursor) +void RenderWidgetHostViewQtDelegateItem::updateCursor(const QCursor &cursor) { setCursor(cursor); } -void RenderWidgetHostViewQtDelegateQuick::resize(int width, int height) +void RenderWidgetHostViewQtDelegateItem::resize(int width, int height) { setSize(QSizeF(width, height)); + if (m_widgetDelegate) + m_widgetDelegate->Resize(width, height); +} + +void RenderWidgetHostViewQtDelegateItem::move(const QPoint &point) +{ + if (m_widgetDelegate && m_isPopup) + m_widgetDelegate->MoveWindow(point); } -void RenderWidgetHostViewQtDelegateQuick::inputMethodStateChanged(bool editorVisible, bool passwordInput) +void RenderWidgetHostViewQtDelegateItem::inputMethodStateChanged(bool editorVisible, bool passwordInput) { setFlag(QQuickItem::ItemAcceptsInputMethod, editorVisible && !passwordInput); if (parentItem()) parentItem()->setFlag(QQuickItem::ItemAcceptsInputMethod, editorVisible && !passwordInput); + if (m_widgetDelegate) + m_widgetDelegate->SetInputMethodEnabled(editorVisible && !passwordInput); + qApp->inputMethod()->update(Qt::ImQueryInput | Qt::ImEnabled | Qt::ImHints); if (qApp->inputMethod()->isVisible() != editorVisible) qApp->inputMethod()->setVisible(editorVisible); } -bool RenderWidgetHostViewQtDelegateQuick::event(QEvent *event) +void RenderWidgetHostViewQtDelegateItem::setWidgetDelegate(WidgetDelegate *delegate) +{ + Q_ASSERT(!m_widgetDelegate || !delegate); + m_widgetDelegate = delegate; + if (m_widgetDelegate) { + if (m_inputMethodHints) + m_widgetDelegate->SetInputMethodHints(m_inputMethodHints); + if (m_clearColor.isValid()) + m_widgetDelegate->SetClearColor(m_clearColor); + if (flags().testFlag(QQuickItem::ItemAcceptsInputMethod)) + m_widgetDelegate->SetInputMethodEnabled(true); + if (m_adapterClient) + m_widgetDelegate->Bind(m_adapterClient); + } +} + +void RenderWidgetHostViewQtDelegateItem::setInputMethodHints(Qt::InputMethodHints hints) +{ + m_inputMethodHints = hints; + if (m_widgetDelegate) + m_widgetDelegate->SetInputMethodHints(hints); +} + +void RenderWidgetHostViewQtDelegateItem::setClearColor(const QColor &color) +{ + m_clearColor = color; + if (m_widgetDelegate) + m_widgetDelegate->SetClearColor(color); +} + +bool RenderWidgetHostViewQtDelegateItem::event(QEvent *event) { if (event->type() == QEvent::ShortcutOverride) return m_client->forwardEvent(event); -#ifndef QT_NO_GESTURES +#if QT_CONFIG(gestures) if (event->type() == QEvent::NativeGesture) return m_client->forwardEvent(event); #endif @@ -183,78 +229,78 @@ bool RenderWidgetHostViewQtDelegateQuick::event(QEvent *event) return QQuickItem::event(event); } -void RenderWidgetHostViewQtDelegateQuick::focusInEvent(QFocusEvent *event) +void RenderWidgetHostViewQtDelegateItem::focusInEvent(QFocusEvent *event) { #if QT_CONFIG(accessibility) - if (QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(this)->focusChild()) { - QAccessibleEvent focusEvent(iface, QAccessible::Focus); - QAccessible::updateAccessibility(&focusEvent); + if (QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(this)) { + if (auto *focusChild = iface->focusChild()) { + QAccessibleEvent focusEvent(focusChild, QAccessible::Focus); + QAccessible::updateAccessibility(&focusEvent); + } } #endif // QT_CONFIG(accessibility) m_client->forwardEvent(event); } -void RenderWidgetHostViewQtDelegateQuick::focusOutEvent(QFocusEvent *event) +void RenderWidgetHostViewQtDelegateItem::focusOutEvent(QFocusEvent *event) { m_client->forwardEvent(event); } -void RenderWidgetHostViewQtDelegateQuick::mousePressEvent(QMouseEvent *event) +void RenderWidgetHostViewQtDelegateItem::mousePressEvent(QMouseEvent *event) { - QQuickItem *parent = parentItem(); - if (!m_isPopup && (parent && parent->property("activeFocusOnPress").toBool())) - forceActiveFocus(); - if (!m_isPopup && parent && !parent->property("activeFocusOnPress").toBool() && !parent->hasActiveFocus()) { - event->ignore(); - return; + if (!m_isPopup && m_widgetDelegate) { + if (m_widgetDelegate->ActiveFocusOnPress()) { + forceActiveFocus(); + } else { + event->ignore(); + return; + } } m_client->forwardEvent(event); } -void RenderWidgetHostViewQtDelegateQuick::mouseMoveEvent(QMouseEvent *event) +void RenderWidgetHostViewQtDelegateItem::mouseMoveEvent(QMouseEvent *event) { - QQuickItem *parent = parentItem(); - if (parent && !parent->property("activeFocusOnPress").toBool() && !parent->hasActiveFocus()) { + if (!m_isPopup && m_widgetDelegate && !m_widgetDelegate->ActiveFocusOnPress()) { event->ignore(); return; } m_client->forwardEvent(event); } -void RenderWidgetHostViewQtDelegateQuick::mouseReleaseEvent(QMouseEvent *event) +void RenderWidgetHostViewQtDelegateItem::mouseReleaseEvent(QMouseEvent *event) { - QQuickItem *parent = parentItem(); - if (!m_isPopup && parent && !parent->property("activeFocusOnPress").toBool() && !parent->hasActiveFocus()) { + if (!m_isPopup && m_widgetDelegate && !m_widgetDelegate->ActiveFocusOnPress()) { event->ignore(); return; } m_client->forwardEvent(event); } -void RenderWidgetHostViewQtDelegateQuick::keyPressEvent(QKeyEvent *event) +void RenderWidgetHostViewQtDelegateItem::keyPressEvent(QKeyEvent *event) { m_client->forwardEvent(event); } -void RenderWidgetHostViewQtDelegateQuick::keyReleaseEvent(QKeyEvent *event) +void RenderWidgetHostViewQtDelegateItem::keyReleaseEvent(QKeyEvent *event) { m_client->forwardEvent(event); } -void RenderWidgetHostViewQtDelegateQuick::wheelEvent(QWheelEvent *event) +void RenderWidgetHostViewQtDelegateItem::wheelEvent(QWheelEvent *event) { m_client->forwardEvent(event); } -void RenderWidgetHostViewQtDelegateQuick::touchEvent(QTouchEvent *event) +void RenderWidgetHostViewQtDelegateItem::touchEvent(QTouchEvent *event) { - QQuickItem *parent = parentItem(); - if (!m_isPopup && parent) { - if (event->type() == QEvent::TouchBegin && parent->property("activeFocusOnPress").toBool()) + if (!m_isPopup && m_widgetDelegate) { + if (event->type() == QEvent::TouchBegin && m_widgetDelegate->ActiveFocusOnPress()) forceActiveFocus(); - if (!parent->property("activeFocusOnPress").toBool() && !parent->hasActiveFocus()) { + if (!m_widgetDelegate->ActiveFocusOnPress()) { event->ignore(); return; } @@ -262,11 +308,9 @@ void RenderWidgetHostViewQtDelegateQuick::touchEvent(QTouchEvent *event) m_client->forwardEvent(event); } -void RenderWidgetHostViewQtDelegateQuick::hoverMoveEvent(QHoverEvent *event) +void RenderWidgetHostViewQtDelegateItem::hoverMoveEvent(QHoverEvent *event) { - QQuickItem *parent = parentItem(); - if ((!m_isPopup && parent && !parent->property("activeFocusOnPress").toBool() - && !parent->hasActiveFocus()) + if ((!m_isPopup && m_widgetDelegate && !m_widgetDelegate->ActiveFocusOnPress()) || event->position() == event->oldPosF()) { event->ignore(); return; @@ -274,28 +318,28 @@ void RenderWidgetHostViewQtDelegateQuick::hoverMoveEvent(QHoverEvent *event) m_client->forwardEvent(event); } -void RenderWidgetHostViewQtDelegateQuick::hoverLeaveEvent(QHoverEvent *event) +void RenderWidgetHostViewQtDelegateItem::hoverLeaveEvent(QHoverEvent *event) { m_client->forwardEvent(event); } -QVariant RenderWidgetHostViewQtDelegateQuick::inputMethodQuery(Qt::InputMethodQuery query) const +QVariant RenderWidgetHostViewQtDelegateItem::inputMethodQuery(Qt::InputMethodQuery query) const { return m_client->inputMethodQuery(query); } -void RenderWidgetHostViewQtDelegateQuick::inputMethodEvent(QInputMethodEvent *event) +void RenderWidgetHostViewQtDelegateItem::inputMethodEvent(QInputMethodEvent *event) { m_client->forwardEvent(event); } -void RenderWidgetHostViewQtDelegateQuick::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) +void RenderWidgetHostViewQtDelegateItem::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) { QQuickItem::geometryChange(newGeometry, oldGeometry); m_client->visualPropertiesChanged(); } -void RenderWidgetHostViewQtDelegateQuick::itemChange(ItemChange change, const ItemChangeData &value) +void RenderWidgetHostViewQtDelegateItem::itemChange(ItemChange change, const ItemChangeData &value) { QQuickItem::itemChange(change, value); if (change == QQuickItem::ItemSceneChange) { @@ -303,8 +347,8 @@ void RenderWidgetHostViewQtDelegateQuick::itemChange(ItemChange change, const It disconnect(c); m_windowConnections.clear(); if (value.window) { - m_windowConnections.append(connect(value.window, SIGNAL(beforeRendering()), - SLOT(onBeforeRendering()), Qt::DirectConnection)); + m_windowConnections.append(connect(value.window, &QQuickWindow::beforeRendering, + this, &RenderWidgetHostViewQtDelegateItem::onBeforeRendering, Qt::DirectConnection)); m_windowConnections.append(connect(value.window, SIGNAL(xChanged(int)), SLOT(onWindowPosChanged()))); m_windowConnections.append(connect(value.window, SIGNAL(yChanged(int)), SLOT(onWindowPosChanged()))); if (!m_isPopup) @@ -312,12 +356,17 @@ void RenderWidgetHostViewQtDelegateQuick::itemChange(ItemChange change, const It } m_client->visualPropertiesChanged(); } else if (change == QQuickItem::ItemVisibleHasChanged) { - if (!m_isPopup && !value.boolValue) - onHide(); + if (value.boolValue) { + m_client->notifyShown(); + } else { + m_client->notifyHidden(); + if (!m_isPopup) + onHide(); + } } } -QSGNode *RenderWidgetHostViewQtDelegateQuick::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) +QSGNode *RenderWidgetHostViewQtDelegateItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) { auto comp = compositor(); if (!comp) @@ -340,16 +389,14 @@ QSGNode *RenderWidgetHostViewQtDelegateQuick::updatePaintNode(QSGNode *oldNode, if (comp->type() == Compositor::Type::Software) { QImage image = comp->image(); node->setTexture(win->createTextureFromImage(image)); +#if QT_CONFIG(opengl) } else if (comp->type() == Compositor::Type::OpenGL) { QQuickWindow::CreateTextureOptions texOpts; -#if QT_CONFIG(opengl) if (comp->hasAlphaChannel()) texOpts.setFlag(QQuickWindow::TextureHasAlphaChannel); int texId = comp->textureId(); node->setTexture(QNativeInterface::QSGOpenGLTexture::fromNative(texId, win, texSize, texOpts)); node->setTextureCoordinatesTransform(QSGImageNode::MirrorVertically); -#else - Q_UNREACHABLE(); #endif } else { Q_UNREACHABLE(); @@ -358,7 +405,7 @@ QSGNode *RenderWidgetHostViewQtDelegateQuick::updatePaintNode(QSGNode *oldNode, return node; } -void RenderWidgetHostViewQtDelegateQuick::onBeforeRendering() +void RenderWidgetHostViewQtDelegateItem::onBeforeRendering() { auto comp = compositor(); if (!comp || comp->type() != Compositor::Type::OpenGL) @@ -366,84 +413,30 @@ void RenderWidgetHostViewQtDelegateQuick::onBeforeRendering() comp->waitForTexture(); } -void RenderWidgetHostViewQtDelegateQuick::onWindowPosChanged() +void RenderWidgetHostViewQtDelegateItem::onWindowPosChanged() { m_client->visualPropertiesChanged(); } -void RenderWidgetHostViewQtDelegateQuick::onHide() +void RenderWidgetHostViewQtDelegateItem::onHide() { QFocusEvent event(QEvent::FocusOut, Qt::OtherFocusReason); m_client->forwardEvent(&event); } -void RenderWidgetHostViewQtDelegateQuick::adapterClientChanged(WebContentsAdapterClient *client) -{ - QQuickWebEngineViewPrivate::bindViewAndWidget( - static_cast<QQuickWebEngineViewPrivate *>(client)->q_func(), this); -} - -#if QT_CONFIG(accessibility) -RenderWidgetHostViewQtDelegateQuickAccessible::RenderWidgetHostViewQtDelegateQuickAccessible(RenderWidgetHostViewQtDelegateQuick *o, QQuickWebEngineView *view) - : QAccessibleObject(o) - , m_view(view) -{ -} - -bool RenderWidgetHostViewQtDelegateQuickAccessible::isValid() const -{ - if (!viewAccessible() || !viewAccessible()->isValid()) - return false; - - return QAccessibleObject::isValid(); -} - -QAccessibleInterface *RenderWidgetHostViewQtDelegateQuickAccessible::parent() const -{ - return viewAccessible()->parent(); -} - -QString RenderWidgetHostViewQtDelegateQuickAccessible::text(QAccessible::Text) const -{ - return QString(); -} - -QAccessible::Role RenderWidgetHostViewQtDelegateQuickAccessible::role() const -{ - return QAccessible::Client; -} - -QAccessible::State RenderWidgetHostViewQtDelegateQuickAccessible::state() const -{ - return viewAccessible()->state(); -} - -QAccessibleInterface *RenderWidgetHostViewQtDelegateQuickAccessible::focusChild() const -{ - return viewAccessible()->focusChild(); -} - -int RenderWidgetHostViewQtDelegateQuickAccessible::childCount() const -{ - return viewAccessible()->childCount(); -} - -QAccessibleInterface *RenderWidgetHostViewQtDelegateQuickAccessible::child(int index) const -{ - return viewAccessible()->child(index); -} - -int RenderWidgetHostViewQtDelegateQuickAccessible::indexOfChild(const QAccessibleInterface *c) const +void RenderWidgetHostViewQtDelegateItem::adapterClientChanged(WebContentsAdapterClient *client) { - return viewAccessible()->indexOfChild(c); + m_adapterClient = client; + if (m_widgetDelegate) + m_widgetDelegate->Bind(client); } -QQuickWebEngineViewAccessible *RenderWidgetHostViewQtDelegateQuickAccessible::viewAccessible() const +void RenderWidgetHostViewQtDelegateItem::unhandledWheelEvent(QWheelEvent *ev) { - return static_cast<QQuickWebEngineViewAccessible *>(QAccessible::queryAccessibleInterface(m_view)); + if (QWindow *w = Window()) { + if (QWindow *p = w->parent()) + qApp->sendEvent(p, ev); + } } -#endif // QT_CONFIG(accessibility) } // namespace QtWebEngineCore - -#include "moc_render_widget_host_view_qt_delegate_quick.cpp" diff --git a/src/webenginequick/render_widget_host_view_qt_delegate_quick.h b/src/core/render_widget_host_view_qt_delegate_item.h index 1580e0614..515f2b28c 100644 --- a/src/webenginequick/render_widget_host_view_qt_delegate_quick.h +++ b/src/core/render_widget_host_view_qt_delegate_item.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2022 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,59 @@ ** ****************************************************************************/ -#ifndef RENDER_WIDGET_HOST_VIEW_QT_DELEGATE_QUICK_H -#define RENDER_WIDGET_HOST_VIEW_QT_DELEGATE_QUICK_H +#ifndef RENDER_WIDGET_HOST_VIEW_QT_DELEGATE_ITEM_H +#define RENDER_WIDGET_HOST_VIEW_QT_DELEGATE_ITEM_H #include "compositor/compositor.h" #include "render_widget_host_view_qt_delegate.h" -#include <QtGui/qaccessibleobject.h> -#include <QtQuick/qquickitem.h> +#include <QtQuick/QQuickItem> QT_BEGIN_NAMESPACE class QQuickWebEngineView; -class QQuickWebEngineViewAccessible; class QQuickWebEngineViewPrivate; +class QWebEnginePage; +class QWebEngineViewPrivate; QT_END_NAMESPACE namespace QtWebEngineCore { class RenderWidgetHostViewQtDelegateClient; +class WebContentsAdapterClient; +class WebEngineQuickWidget; -class RenderWidgetHostViewQtDelegateQuick : public QQuickItem, - public RenderWidgetHostViewQtDelegate, - public Compositor::Observer +class WidgetDelegate +{ +public: + virtual ~WidgetDelegate() = default; + virtual void InitAsPopup(const QRect &screenRect) = 0; + virtual void SetInputMethodEnabled(bool) { } + virtual void SetInputMethodHints(Qt::InputMethodHints) { } + virtual void SetClearColor(const QColor &) { } + virtual bool ActiveFocusOnPress() = 0; + virtual void MoveWindow(const QPoint & ) { } + virtual void Bind(WebContentsAdapterClient *) = 0; + virtual void Unbind() = 0; + virtual void Destroy() = 0; + virtual void Resize(int, int) { } + virtual QWindow *Window() { return nullptr; } +}; + +// Useful information keyboard and mouse QEvent propagation. +// A RenderWidgetHostViewQtDelegateItem instance initialized as a popup will receive +// no keyboard focus (so all keyboard QEvents will be sent to the parent RWHVQD instance), +// but will still receive mouse input (all mouse QEvent moves and clicks will be given to the popup +// RWHVQD instance, and the mouse interaction area covers the surface of the whole parent +// QWebEngineView, and not only the smaller surface that an HTML select popup would occupy). +class Q_WEBENGINECORE_PRIVATE_EXPORT RenderWidgetHostViewQtDelegateItem + : public QQuickItem + , public RenderWidgetHostViewQtDelegate + , public Compositor::Observer { Q_OBJECT public: - RenderWidgetHostViewQtDelegateQuick(RenderWidgetHostViewQtDelegateClient *client, bool isPopup); - ~RenderWidgetHostViewQtDelegateQuick(); + RenderWidgetHostViewQtDelegateItem(RenderWidgetHostViewQtDelegateClient *client, bool isPopup); + ~RenderWidgetHostViewQtDelegateItem(); void initAsPopup(const QRect&) override; QRectF viewGeometry() const override; @@ -75,16 +101,18 @@ public: void show() override; void hide() override; bool isVisible() const override; - QWindow* window() const override; + QWindow *Window() const override; void updateCursor(const QCursor &) override; void resize(int width, int height) override; - void move(const QPoint&) override { } - void inputMethodStateChanged(bool editorVisible, bool isPasswordInput) override; - void setInputMethodHints(Qt::InputMethodHints) override { } - // The QtQuick view doesn't have a backbuffer of its own and doesn't need this - void setClearColor(const QColor &) override { } + void move(const QPoint &screenPos) override; + void inputMethodStateChanged(bool editorVisible, bool passwordInput) override; + void setInputMethodHints(Qt::InputMethodHints) override; + void setClearColor(const QColor &color) override; + void unhandledWheelEvent(QWheelEvent *ev) override; + void readyToSwap() override; - void adapterClientChanged(WebContentsAdapterClient *client) override; + + void setWidgetDelegate(WidgetDelegate *delegate); protected: bool event(QEvent *event) override; @@ -105,43 +133,29 @@ protected: void itemChange(ItemChange change, const ItemChangeData &value) override; QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) override; + void adapterClientChanged(WebContentsAdapterClient *client) override; + private Q_SLOTS: void onBeforeRendering(); void onWindowPosChanged(); void onHide(); private: + friend QWebEngineViewPrivate; friend QQuickWebEngineViewPrivate; + friend WebEngineQuickWidget; RenderWidgetHostViewQtDelegateClient *m_client; - QList<QMetaObject::Connection> m_windowConnections; bool m_isPopup; + QColor m_clearColor; + Qt::InputMethodHints m_inputMethodHints = {}; + QList<QMetaObject::Connection> m_windowConnections; + WebContentsAdapterClient *m_adapterClient = nullptr; + QWebEnginePage *m_page = nullptr; QQuickWebEngineView *m_view = nullptr; + WidgetDelegate *m_widgetDelegate = nullptr; }; -#if QT_CONFIG(accessibility) -class RenderWidgetHostViewQtDelegateQuickAccessible : public QAccessibleObject -{ -public: - RenderWidgetHostViewQtDelegateQuickAccessible(RenderWidgetHostViewQtDelegateQuick *o, QQuickWebEngineView *view); - - bool isValid() const override; - QAccessibleInterface *parent() const override; - QString text(QAccessible::Text t) const override; - QAccessible::Role role() const override; - QAccessible::State state() const override; - - QAccessibleInterface *focusChild() const override; - int childCount() const override; - QAccessibleInterface *child(int index) const override; - int indexOfChild(const QAccessibleInterface *) const override; - -private: - QQuickWebEngineViewAccessible *viewAccessible() const; - QQuickWebEngineView *m_view; -}; -#endif // QT_CONFIG(accessibility) - } // namespace QtWebEngineCore -#endif +#endif // RENDER_WIDGET_HOST_VIEW_QT_DELEGATE_ITEM_H diff --git a/src/core/web_contents_delegate_qt.cpp b/src/core/web_contents_delegate_qt.cpp index 292043f78..bbd15a35d 100644 --- a/src/core/web_contents_delegate_qt.cpp +++ b/src/core/web_contents_delegate_qt.cpp @@ -629,8 +629,8 @@ void WebContentsDelegateQt::SetContentsBounds(content::WebContents *source, cons QRect frameGeometry(toQt(bounds)); QRect geometry; if (RenderWidgetHostViewQt *rwhv = static_cast<RenderWidgetHostViewQt*>(web_contents()->GetRenderWidgetHostView())) { - if (rwhv->delegate() && rwhv->delegate()->window()) - geometry = frameGeometry.marginsRemoved(rwhv->delegate()->window()->frameMargins()); + if (rwhv->delegate() && rwhv->delegate()->Window()) + geometry = frameGeometry.marginsRemoved(rwhv->delegate()->Window()->frameMargins()); } m_viewClient->requestGeometryChange(geometry, frameGeometry); } diff --git a/src/webenginequick/CMakeLists.txt b/src/webenginequick/CMakeLists.txt index 3800f8386..ebe1ddf54 100644 --- a/src/webenginequick/CMakeLists.txt +++ b/src/webenginequick/CMakeLists.txt @@ -34,7 +34,7 @@ qt_internal_add_qml_module(WebEngineQuick api/qquickwebengineforeigntypes_p.h api/qtwebenginequickglobal.cpp api/qtwebenginequickglobal.h api/qtwebenginequickglobal_p.h - render_widget_host_view_qt_delegate_quick.cpp render_widget_host_view_qt_delegate_quick.h + qquickwebengine_accessible.cpp qquickwebengine_accessible.h render_widget_host_view_qt_delegate_quickwindow.cpp render_widget_host_view_qt_delegate_quickwindow.h ui_delegates_manager.cpp ui_delegates_manager.h DEFINES diff --git a/src/webenginequick/api/qquickwebengineview.cpp b/src/webenginequick/api/qquickwebengineview.cpp index 7eb5a8677..24c059d39 100644 --- a/src/webenginequick/api/qquickwebengineview.cpp +++ b/src/webenginequick/api/qquickwebengineview.cpp @@ -59,7 +59,8 @@ #include "file_picker_controller.h" #include "find_text_helper.h" #include "javascript_dialog_controller.h" -#include "render_widget_host_view_qt_delegate_quick.h" +#include "qquickwebengine_accessible.h" +#include "render_widget_host_view_qt_delegate_item.h" #include "render_widget_host_view_qt_delegate_quickwindow.h" #include "touch_selection_menu_controller.h" #include "ui_delegates_manager.h" @@ -139,14 +140,61 @@ Q_STATIC_ASSERT(static_cast<int>(QQuickWebEngineView::LoadSucceededStatus) == st QT_WARNING_POP #endif -#ifndef QT_NO_ACCESSIBILITY +class WebEngineQuickWidgetDelegate : public QtWebEngineCore::WidgetDelegate +{ +public: + WebEngineQuickWidgetDelegate(QtWebEngineCore::RenderWidgetHostViewQtDelegateItem *item, QQuickWebEngineView *parent) + : m_contentItem(item) + , m_parentView(parent) + { + } + + ~WebEngineQuickWidgetDelegate() override + { + if (m_contentItem) + m_contentItem->setWidgetDelegate(nullptr); + } + + void InitAsPopup(const QRect &screenRect) override + { + Q_UNUSED(screenRect); + Q_UNREACHABLE(); + } + + void Bind(WebContentsAdapterClient *client) override + { + QQuickWebEngineViewPrivate::bindViewAndWidget( + static_cast<QQuickWebEngineViewPrivate *>(client)->q_func(), m_contentItem); + } + + void Unbind() override + { + QQuickWebEngineViewPrivate::bindViewAndWidget(nullptr, m_contentItem); + } + + void Destroy() override + { + delete this; + } + + bool ActiveFocusOnPress() override + { + return m_parentView->property("activeFocusOnPress").toBool() || m_parentView->hasActiveFocus(); + } + +private: + QPointer<RenderWidgetHostViewQtDelegateItem> m_contentItem; // deleted by core + QPointer<QQuickWebEngineView> m_parentView; +}; + +#if QT_CONFIG(accessibility) static QAccessibleInterface *webAccessibleFactory(const QString &, QObject *object) { if (QQuickWebEngineView *v = qobject_cast<QQuickWebEngineView*>(object)) return new QQuickWebEngineViewAccessible(v); - return 0; + return nullptr; } -#endif // QT_NO_ACCESSIBILITY +#endif // QT_CONFIG(accessibility) static QLatin1String defaultMimeType("text/html;charset=UTF-8"); @@ -174,9 +222,9 @@ QQuickWebEngineViewPrivate::QQuickWebEngineViewPrivate() { memset(actions, 0, sizeof(actions)); -#ifndef QT_NO_ACCESSIBILITY +#if QT_CONFIG(accessibility) QAccessible::installFactory(&webAccessibleFactory); -#endif // QT_NO_ACCESSIBILITY +#endif // QT_CONFIG(accessibility) } QQuickWebEngineViewPrivate::~QQuickWebEngineViewPrivate() @@ -234,22 +282,26 @@ UIDelegatesManager *QQuickWebEngineViewPrivate::ui() RenderWidgetHostViewQtDelegate *QQuickWebEngineViewPrivate::CreateRenderWidgetHostViewQtDelegate(RenderWidgetHostViewQtDelegateClient *client) { - return new RenderWidgetHostViewQtDelegateQuick(client, /*isPopup = */ false); + Q_Q(QQuickWebEngineView); + auto *item = new RenderWidgetHostViewQtDelegateItem(client, /*isPopup = */ false); + item->setWidgetDelegate(new WebEngineQuickWidgetDelegate(item, q)); + return item; } RenderWidgetHostViewQtDelegate *QQuickWebEngineViewPrivate::CreateRenderWidgetHostViewQtDelegateForPopup(RenderWidgetHostViewQtDelegateClient *client) { Q_Q(QQuickWebEngineView); const bool hasWindowCapability = QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::MultipleWindows); - RenderWidgetHostViewQtDelegateQuick *quickDelegate = new RenderWidgetHostViewQtDelegateQuick(client, /*isPopup = */ true); + RenderWidgetHostViewQtDelegateItem *quickDelegate = new RenderWidgetHostViewQtDelegateItem(client, /*isPopup = */ true); if (hasWindowCapability) { RenderWidgetHostViewQtDelegateQuickWindow *wrapperWindow = new RenderWidgetHostViewQtDelegateQuickWindow(quickDelegate, q->window()); + quickDelegate->setWidgetDelegate(wrapperWindow); wrapperWindow->setVirtualParent(q); - quickDelegate->setParentItem(wrapperWindow->contentItem()); - return wrapperWindow; + return quickDelegate; } quickDelegate->setParentItem(q); + quickDelegate->setWidgetDelegate(new WebEngineQuickWidgetDelegate(quickDelegate, q)); quickDelegate->show(); return quickDelegate; } @@ -715,74 +767,6 @@ void QQuickWebEngineViewPrivate::visibleChanged(bool visible) Q_UNUSED(visible); } -#ifndef QT_NO_ACCESSIBILITY -QQuickWebEngineViewAccessible::QQuickWebEngineViewAccessible(QQuickWebEngineView *o) - : QAccessibleObject(o) -{} - -bool QQuickWebEngineViewAccessible::isValid() const -{ - if (!QAccessibleObject::isValid()) - return false; - - if (!engineView() || !engineView()->d_func()) - return false; - - return true; -} - -QAccessibleInterface *QQuickWebEngineViewAccessible::parent() const -{ - QQuickItem *parent = engineView()->parentItem(); - QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(parent); - if (!iface) - return QAccessible::queryAccessibleInterface(engineView()->window()); - return iface; -} - -QAccessibleInterface *QQuickWebEngineViewAccessible::focusChild() const -{ - if (child(0) && child(0)->focusChild()) - return child(0)->focusChild(); - return const_cast<QQuickWebEngineViewAccessible *>(this); -} - -int QQuickWebEngineViewAccessible::childCount() const -{ - return child(0) ? 1 : 0; -} - -QAccessibleInterface *QQuickWebEngineViewAccessible::child(int index) const -{ - if (index == 0 && isValid()) - return engineView()->d_func()->adapter->browserAccessible(); - return nullptr; -} - -int QQuickWebEngineViewAccessible::indexOfChild(const QAccessibleInterface *c) const -{ - if (child(0) && c == child(0)) - return 0; - return -1; -} - -QString QQuickWebEngineViewAccessible::text(QAccessible::Text) const -{ - return QString(); -} - -QAccessible::Role QQuickWebEngineViewAccessible::role() const -{ - return QAccessible::Client; -} - -QAccessible::State QQuickWebEngineViewAccessible::state() const -{ - QAccessible::State s; - return s; -} -#endif // QT_NO_ACCESSIBILITY - class WebContentsAdapterOwner : public QObject { public: @@ -912,7 +896,7 @@ void QQuickWebEngineViewPrivate::setFullScreenMode(bool fullscreen) } void QQuickWebEngineViewPrivate::bindViewAndWidget(QQuickWebEngineView *view, - RenderWidgetHostViewQtDelegateQuick *widget) + RenderWidgetHostViewQtDelegateItem *widget) { auto oldWidget = view ? view->d_func()->widget : nullptr; auto oldView = widget ? widget->m_view : nullptr; @@ -940,8 +924,8 @@ void QQuickWebEngineViewPrivate::bindViewAndWidget(QQuickWebEngineView *view, view->d_func()->widgetChanged(oldWidget, widget); } -void QQuickWebEngineViewPrivate::widgetChanged(RenderWidgetHostViewQtDelegateQuick *oldWidget, - RenderWidgetHostViewQtDelegateQuick *newWidget) +void QQuickWebEngineViewPrivate::widgetChanged(QtWebEngineCore::RenderWidgetHostViewQtDelegateItem *oldWidget, + QtWebEngineCore::RenderWidgetHostViewQtDelegateItem *newWidget) { Q_Q(QQuickWebEngineView); diff --git a/src/webenginequick/api/qquickwebengineview_p.h b/src/webenginequick/api/qquickwebengineview_p.h index fb736085b..46b92b9c6 100644 --- a/src/webenginequick/api/qquickwebengineview_p.h +++ b/src/webenginequick/api/qquickwebengineview_p.h @@ -57,10 +57,6 @@ #include <QtQml/qqmlregistration.h> #include <QtQuick/qquickitem.h> -namespace QtWebEngineCore { -class RenderWidgetHostViewQtDelegateQuick; -} - QT_BEGIN_NAMESPACE class QQmlWebChannel; @@ -589,7 +585,6 @@ private: Q_DECLARE_PRIVATE(QQuickWebEngineView) QScopedPointer<QQuickWebEngineViewPrivate> d_ptr; - friend class QtWebEngineCore::RenderWidgetHostViewQtDelegateQuick; friend class QQuickContextMenuBuilder; friend class FaviconImageResponse; friend class FaviconImageResponseRunnable; diff --git a/src/webenginequick/api/qquickwebengineview_p_p.h b/src/webenginequick/api/qquickwebengineview_p_p.h index 2096f79c6..fe9f78322 100644 --- a/src/webenginequick/api/qquickwebengineview_p_p.h +++ b/src/webenginequick/api/qquickwebengineview_p_p.h @@ -66,7 +66,7 @@ #include <QtGui/qaccessibleobject.h> namespace QtWebEngineCore { -class RenderWidgetHostViewQtDelegateQuick; +class RenderWidgetHostViewQtDelegateItem; class TouchSelectionMenuController; class UIDelegatesManager; class WebContentsAdapter; @@ -174,9 +174,9 @@ public: void ensureContentsAdapter(); void setFullScreenMode(bool); - static void bindViewAndWidget(QQuickWebEngineView *view, QtWebEngineCore::RenderWidgetHostViewQtDelegateQuick *widget); - void widgetChanged(QtWebEngineCore::RenderWidgetHostViewQtDelegateQuick *oldWidget, - QtWebEngineCore::RenderWidgetHostViewQtDelegateQuick *newWidget); + static void bindViewAndWidget(QQuickWebEngineView *view, QtWebEngineCore::RenderWidgetHostViewQtDelegateItem *widget); + void widgetChanged(QtWebEngineCore::RenderWidgetHostViewQtDelegateItem *oldWidget, + QtWebEngineCore::RenderWidgetHostViewQtDelegateItem *newWidget); QQuickWebEngineProfile *m_profile; QSharedPointer<QtWebEngineCore::WebContentsAdapter> adapter; @@ -200,7 +200,7 @@ public: bool m_defaultAudioMuted; bool m_isBeingAdopted; mutable QQuickWebEngineAction *actions[QQuickWebEngineView::WebActionCount]; - QtWebEngineCore::RenderWidgetHostViewQtDelegateQuick *widget = nullptr; + QtWebEngineCore::RenderWidgetHostViewQtDelegateItem *widget = nullptr; bool profileInitialized() const; QQuickWebEngineScriptCollection *getUserScripts(); @@ -216,26 +216,6 @@ private: QQmlComponent *m_touchHandleDelegate; }; -#ifndef QT_NO_ACCESSIBILITY -class QQuickWebEngineViewAccessible : public QAccessibleObject -{ -public: - QQuickWebEngineViewAccessible(QQuickWebEngineView *o); - bool isValid() const override; - QAccessibleInterface *parent() const override; - QAccessibleInterface *focusChild() const override; - int childCount() const override; - QAccessibleInterface *child(int index) const override; - int indexOfChild(const QAccessibleInterface*) const override; - QString text(QAccessible::Text) const override; - QAccessible::Role role() const override; - QAccessible::State state() const override; - -private: - QQuickWebEngineView *engineView() const { return static_cast<QQuickWebEngineView*>(object()); } -}; -#endif // QT_NO_ACCESSIBILITY - class QQuickContextMenuBuilder : public QtWebEngineCore::RenderViewContextMenuQt { public: diff --git a/src/webenginequick/qquickwebengine_accessible.cpp b/src/webenginequick/qquickwebengine_accessible.cpp new file mode 100644 index 000000000..8d9f2bd63 --- /dev/null +++ b/src/webenginequick/qquickwebengine_accessible.cpp @@ -0,0 +1,186 @@ +/**************************************************************************** +** +** Copyright (C) 2022 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 "qquickwebengine_accessible.h" + +#include <QQuickItem> +#include <QQuickWindow> + +#include "api/qquickwebengineview_p.h" +#include "api/qquickwebengineview_p_p.h" +#include "web_contents_adapter.h" + + +#if QT_CONFIG(accessibility) +QT_BEGIN_NAMESPACE +QQuickWebEngineViewAccessible::QQuickWebEngineViewAccessible(QQuickWebEngineView *o) + : QAccessibleObject(o) +{} + +bool QQuickWebEngineViewAccessible::isValid() const +{ + if (!QAccessibleObject::isValid()) + return false; + + if (!engineView() || !engineView()->d_func()) + return false; + + return true; +} + +QAccessibleInterface *QQuickWebEngineViewAccessible::parent() const +{ + QQuickItem *parent = engineView()->parentItem(); + QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(parent); + if (!iface) + return QAccessible::queryAccessibleInterface(engineView()->window()); + return iface; +} + +QAccessibleInterface *QQuickWebEngineViewAccessible::focusChild() const +{ + if (child(0) && child(0)->focusChild()) + return child(0)->focusChild(); + return const_cast<QQuickWebEngineViewAccessible *>(this); +} + +int QQuickWebEngineViewAccessible::childCount() const +{ + return child(0) ? 1 : 0; +} + +QAccessibleInterface *QQuickWebEngineViewAccessible::child(int index) const +{ + if (index == 0 && isValid()) + return engineView()->d_func()->adapter->browserAccessible(); + return nullptr; +} + +int QQuickWebEngineViewAccessible::indexOfChild(const QAccessibleInterface *c) const +{ + if (child(0) && c == child(0)) + return 0; + return -1; +} + +QString QQuickWebEngineViewAccessible::text(QAccessible::Text) const +{ + return QString(); +} + +QAccessible::Role QQuickWebEngineViewAccessible::role() const +{ + return QAccessible::Client; +} + +QAccessible::State QQuickWebEngineViewAccessible::state() const +{ + QAccessible::State s; + return s; +} + +QQuickWebEngineView *QQuickWebEngineViewAccessible::engineView() const +{ + return static_cast<QQuickWebEngineView*>(object()); +} + +QT_END_NAMESPACE + +namespace QtWebEngineCore { + +RenderWidgetHostViewQtDelegateQuickAccessible::RenderWidgetHostViewQtDelegateQuickAccessible(QObject *o, QQuickWebEngineView *view) + : QAccessibleObject(o) + , m_view(view) +{ +} + +bool RenderWidgetHostViewQtDelegateQuickAccessible::isValid() const +{ + if (!viewAccessible() || !viewAccessible()->isValid()) + return false; + + return QAccessibleObject::isValid(); +} + +QAccessibleInterface *RenderWidgetHostViewQtDelegateQuickAccessible::parent() const +{ + return viewAccessible()->parent(); +} + +QString RenderWidgetHostViewQtDelegateQuickAccessible::text(QAccessible::Text) const +{ + return QString(); +} + +QAccessible::Role RenderWidgetHostViewQtDelegateQuickAccessible::role() const +{ + return QAccessible::Client; +} + +QAccessible::State RenderWidgetHostViewQtDelegateQuickAccessible::state() const +{ + return viewAccessible()->state(); +} + +QAccessibleInterface *RenderWidgetHostViewQtDelegateQuickAccessible::focusChild() const +{ + return viewAccessible()->focusChild(); +} + +int RenderWidgetHostViewQtDelegateQuickAccessible::childCount() const +{ + return viewAccessible()->childCount(); +} + +QAccessibleInterface *RenderWidgetHostViewQtDelegateQuickAccessible::child(int index) const +{ + return viewAccessible()->child(index); +} + +int RenderWidgetHostViewQtDelegateQuickAccessible::indexOfChild(const QAccessibleInterface *c) const +{ + return viewAccessible()->indexOfChild(c); +} + +QQuickWebEngineViewAccessible *RenderWidgetHostViewQtDelegateQuickAccessible::viewAccessible() const +{ + return static_cast<QQuickWebEngineViewAccessible *>(QAccessible::queryAccessibleInterface(m_view)); +} +} // namespace QtWebEngineCore +#endif // QT_CONFIG(accessibility) diff --git a/src/webenginequick/qquickwebengine_accessible.h b/src/webenginequick/qquickwebengine_accessible.h new file mode 100644 index 000000000..0005ed9cc --- /dev/null +++ b/src/webenginequick/qquickwebengine_accessible.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2022 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 QQUICKWEBENGINE_ACCESSIBLE_H +#define QQUICKWEBENGINE_ACCESSIBLE_H + +#include <QtCore/qpointer.h> +#include <QtGui/qaccessibleobject.h> + +#if QT_CONFIG(accessibility) + +QT_BEGIN_NAMESPACE +class QQuickWebEngineView; + +class QQuickWebEngineViewAccessible : public QAccessibleObject +{ +public: + QQuickWebEngineViewAccessible(QQuickWebEngineView *o); + bool isValid() const override; + QAccessibleInterface *parent() const override; + QAccessibleInterface *focusChild() const override; + int childCount() const override; + QAccessibleInterface *child(int index) const override; + int indexOfChild(const QAccessibleInterface *) const override; + QString text(QAccessible::Text) const override; + QAccessible::Role role() const override; + QAccessible::State state() const override; + +private: + QQuickWebEngineView *engineView() const; +}; + +QT_END_NAMESPACE + +namespace QtWebEngineCore { +class RenderWidgetHostViewQtDelegateQuickAccessible : public QAccessibleObject +{ +public: + RenderWidgetHostViewQtDelegateQuickAccessible(QObject *o, QQuickWebEngineView *view); + + bool isValid() const override; + QAccessibleInterface *parent() const override; + QString text(QAccessible::Text t) const override; + QAccessible::Role role() const override; + QAccessible::State state() const override; + + QAccessibleInterface *focusChild() const override; + int childCount() const override; + QAccessibleInterface *child(int index) const override; + int indexOfChild(const QAccessibleInterface *) const override; + +private: + QQuickWebEngineViewAccessible *viewAccessible() const; + QPointer<QQuickWebEngineView> m_view; +}; +} // namespace QtWebEngineCore + +#endif // QT_CONFIG(accessibility) + +#endif // QQUICKWEBENGINE_ACCESSIBLE_H diff --git a/src/webenginequick/render_widget_host_view_qt_delegate_quickwindow.cpp b/src/webenginequick/render_widget_host_view_qt_delegate_quickwindow.cpp index 7cae38b2e..911d10c8a 100644 --- a/src/webenginequick/render_widget_host_view_qt_delegate_quickwindow.cpp +++ b/src/webenginequick/render_widget_host_view_qt_delegate_quickwindow.cpp @@ -37,10 +37,9 @@ ** ****************************************************************************/ -#include "render_widget_host_view_qt_delegate_quick.h" #include "render_widget_host_view_qt_delegate_quickwindow.h" -#include <QtQuick/qquickitem.h> +#include "api/qquickwebengineview_p_p.h" namespace QtWebEngineCore { @@ -68,14 +67,19 @@ static inline QPointF transformPoint(const QPointF &point, const QTransform &tra } RenderWidgetHostViewQtDelegateQuickWindow::RenderWidgetHostViewQtDelegateQuickWindow( - RenderWidgetHostViewQtDelegateQuick *realDelegate, QWindow *parent) + RenderWidgetHostViewQtDelegateItem *realDelegate, QWindow *parent) : QQuickWindow(parent), m_realDelegate(realDelegate), m_virtualParent(nullptr), m_rotated(false) { setFlags(Qt::Tool | Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint | Qt::WindowDoesNotAcceptFocus); + realDelegate->setParentItem(contentItem()); } RenderWidgetHostViewQtDelegateQuickWindow::~RenderWidgetHostViewQtDelegateQuickWindow() { + if (m_realDelegate) { + m_realDelegate->setWidgetDelegate(nullptr); + m_realDelegate->setParentItem(nullptr); + } } void RenderWidgetHostViewQtDelegateQuickWindow::setVirtualParent(QQuickItem *virtualParent) @@ -86,9 +90,9 @@ void RenderWidgetHostViewQtDelegateQuickWindow::setVirtualParent(QQuickItem *vir // rect is window geometry in form of parent window offset + offset in scene coordinates // chromium knows nothing about local transformation -void RenderWidgetHostViewQtDelegateQuickWindow::initAsPopup(const QRect &rect) +void RenderWidgetHostViewQtDelegateQuickWindow::InitAsPopup(const QRect &rect) { - m_rotated = m_virtualParent->parentItem()->rotation() > 0; + m_rotated = m_virtualParent->rotation() > 0 || m_virtualParent->parentItem()->rotation() > 0; if (m_rotated) { // code below tries to cover the case where webengine view is rotated, // the code assumes the rotation is in the form of 90, 180, 270 degrees @@ -104,7 +108,6 @@ void RenderWidgetHostViewQtDelegateQuickWindow::initAsPopup(const QRect &rect) QPointF br = transformPoint(rect.bottomRight(), transform, offset, m_virtualParent); QRectF popupRect(tl, br); popupRect = popupRect.normalized(); - m_realDelegate->setSize(rect.size()); // include offset from parent window popupRect.moveTo(popupRect.topLeft() - offset); setGeometry(popupRect.adjusted(0, 0, 1, 1).toRect()); @@ -115,64 +118,51 @@ void RenderWidgetHostViewQtDelegateQuickWindow::initAsPopup(const QRect &rect) m_realDelegate->setTransformOrigin(QQuickItem::Center); m_realDelegate->setRotation(m_virtualParent->parentItem()->rotation()); } else { - m_realDelegate->setSize(rect.size()); QRect geometry(rect); geometry.moveTo(rect.topLeft() - getOffset(m_virtualParent)); setGeometry(geometry); } + m_realDelegate->show(); raise(); show(); } -QRectF RenderWidgetHostViewQtDelegateQuickWindow::viewGeometry() const -{ - return m_rotated ? m_rect : geometry(); -} - -QRect RenderWidgetHostViewQtDelegateQuickWindow::windowGeometry() const +void RenderWidgetHostViewQtDelegateQuickWindow::Resize(int width, int height) { - return m_rotated ? m_rect : frameGeometry(); -} - -void RenderWidgetHostViewQtDelegateQuickWindow::show() -{ - QQuickWindow::show(); - m_realDelegate->show(); + if (!m_rotated) + QQuickWindow::resize(width, height); } -void RenderWidgetHostViewQtDelegateQuickWindow::hide() +void RenderWidgetHostViewQtDelegateQuickWindow::MoveWindow(const QPoint &screenPos) { - QQuickWindow::hide(); - m_realDelegate->hide(); + if (!m_rotated) + QQuickWindow::setPosition(screenPos - getOffset(m_virtualParent)); } -bool RenderWidgetHostViewQtDelegateQuickWindow::isVisible() const +void RenderWidgetHostViewQtDelegateQuickWindow::SetClearColor(const QColor &color) { - return QQuickWindow::isVisible(); + QQuickWindow::setColor(color); } -QWindow *RenderWidgetHostViewQtDelegateQuickWindow::window() const +bool RenderWidgetHostViewQtDelegateQuickWindow::ActiveFocusOnPress() { - return const_cast<RenderWidgetHostViewQtDelegateQuickWindow*>(this); + return false; } -void RenderWidgetHostViewQtDelegateQuickWindow::updateCursor(const QCursor &cursor) +void RenderWidgetHostViewQtDelegateQuickWindow::Bind(QtWebEngineCore::WebContentsAdapterClient *client) { - setCursor(cursor); + QQuickWebEngineViewPrivate::bindViewAndWidget( + static_cast<QQuickWebEngineViewPrivate *>(client)->q_func(), m_realDelegate.data()); } -void RenderWidgetHostViewQtDelegateQuickWindow::resize(int width, int height) +void RenderWidgetHostViewQtDelegateQuickWindow::Unbind() { - if (!m_rotated) { - QQuickWindow::resize(width, height); - m_realDelegate->resize(width, height); - } + QQuickWebEngineViewPrivate::bindViewAndWidget(nullptr, m_realDelegate.data()); } -void RenderWidgetHostViewQtDelegateQuickWindow::move(const QPoint &screenPos) +void RenderWidgetHostViewQtDelegateQuickWindow::Destroy() { - if (!m_rotated) - QQuickWindow::setPosition(screenPos - getOffset(m_virtualParent)); + deleteLater(); } } // namespace QtWebEngineCore diff --git a/src/webenginequick/render_widget_host_view_qt_delegate_quickwindow.h b/src/webenginequick/render_widget_host_view_qt_delegate_quickwindow.h index f7dfd1a05..1b94698ff 100644 --- a/src/webenginequick/render_widget_host_view_qt_delegate_quickwindow.h +++ b/src/webenginequick/render_widget_host_view_qt_delegate_quickwindow.h @@ -41,43 +41,33 @@ #define RENDER_WIDGET_HOST_VIEW_QT_DELEGATE_QUICKWINDOW_H #include "render_widget_host_view_qt_delegate.h" +#include "render_widget_host_view_qt_delegate_item.h" -#include <QtCore/qscopedpointer.h> +#include <QtCore/qpointer.h> #include <QtQuick/qquickwindow.h> namespace QtWebEngineCore { -class RenderWidgetHostViewQtDelegateQuick; - -class RenderWidgetHostViewQtDelegateQuickWindow : public QQuickWindow , public RenderWidgetHostViewQtDelegate { +class RenderWidgetHostViewQtDelegateQuickWindow : public QQuickWindow , public WidgetDelegate { public: - RenderWidgetHostViewQtDelegateQuickWindow(RenderWidgetHostViewQtDelegateQuick *realDelegate, + RenderWidgetHostViewQtDelegateQuickWindow(RenderWidgetHostViewQtDelegateItem *realDelegate, QWindow *parent); ~RenderWidgetHostViewQtDelegateQuickWindow(); - void initAsPopup(const QRect&) override; - QRectF viewGeometry() const override; - QRect windowGeometry() const override; - void setKeyboardFocus() override {} - bool hasKeyboardFocus() override { return false; } - void lockMouse() override {} - void unlockMouse() override {} - void show() override; - void hide() override; - bool isVisible() const override; - QWindow* window() const override; - void updateCursor(const QCursor &) override; - void resize(int width, int height) override; - void move(const QPoint &screenPos) override; - void inputMethodStateChanged(bool, bool) override {} - void setInputMethodHints(Qt::InputMethodHints) override { } - void setClearColor(const QColor &) override { } - void adapterClientChanged(WebContentsAdapterClient *) override { } + void InitAsPopup(const QRect &screenRect) override; + void SetClearColor(const QColor &) override; + bool ActiveFocusOnPress() override; + void MoveWindow(const QPoint &) override; + void Bind(WebContentsAdapterClient *) override; + void Unbind() override; + void Destroy() override; + void Resize(int width, int height) override; + void setVirtualParent(QQuickItem *virtualParent); private: - QScopedPointer<RenderWidgetHostViewQtDelegateQuick> m_realDelegate; + QPointer<RenderWidgetHostViewQtDelegateItem> m_realDelegate; QQuickItem *m_virtualParent; QRect m_rect; bool m_rotated; diff --git a/src/webenginewidgets/CMakeLists.txt b/src/webenginewidgets/CMakeLists.txt index 6a25e7297..1aa4ae1e2 100644 --- a/src/webenginewidgets/CMakeLists.txt +++ b/src/webenginewidgets/CMakeLists.txt @@ -8,7 +8,7 @@ qt_internal_add_module(WebEngineWidgets api/qtwebenginewidgetsglobal.h api/qwebenginenotificationpresenter.cpp api/qwebenginenotificationpresenter_p.h api/qwebengineview.cpp api/qwebengineview.h api/qwebengineview_p.h - render_widget_host_view_qt_delegate_widget.cpp render_widget_host_view_qt_delegate_widget.h + qwebengine_accessible.cpp qwebengine_accessible.h DEFINES QT_BUILD_WEBENGINEWIDGETS_LIB INCLUDE_DIRECTORIES diff --git a/src/webenginewidgets/api/qwebengineview.cpp b/src/webenginewidgets/api/qwebengineview.cpp index 8016b2d57..b3bba7d9e 100644 --- a/src/webenginewidgets/api/qwebengineview.cpp +++ b/src/webenginewidgets/api/qwebengineview.cpp @@ -40,7 +40,9 @@ #include "qwebenginenotificationpresenter_p.h" #include "qwebengineview.h" #include "qwebengineview_p.h" -#include "render_widget_host_view_qt_delegate_widget.h" +#include "render_widget_host_view_qt_delegate_client.h" +#include "render_widget_host_view_qt_delegate_item.h" +#include "qwebengine_accessible.h" #include <QtWebEngineCore/private/qwebenginepage_p.h> #include <QtWebEngineCore/qwebenginecontextmenurequest.h> @@ -57,6 +59,7 @@ #include <QIcon> #include <QStyle> #include <QGuiApplication> +#include <QQuickWidget> #if QT_CONFIG(action) #include <QAction> @@ -91,6 +94,286 @@ #include <QThread> #endif +namespace QtWebEngineCore { +class WebEngineQuickWidget : public QQuickWidget, public WidgetDelegate +{ +public: + WebEngineQuickWidget(RenderWidgetHostViewQtDelegateItem *widget, QWidget *parent) + : QQuickWidget(parent) + , m_contentItem(widget) + { + setFocusPolicy(Qt::StrongFocus); + setMouseTracking(true); + setAttribute(Qt::WA_AcceptTouchEvents); + setAttribute(Qt::WA_OpaquePaintEvent); + setAttribute(Qt::WA_AlwaysShowToolTips); + + QQuickItem *root = new QQuickItem(); // Indirection so we don't delete m_contentItem + setContent(QUrl(), nullptr, root); + root->setFlags(QQuickItem::ItemHasContents); + root->setFocus(true); + root->setVisible(true); + m_contentItem->setParentItem(root); + + connectRemoveParentBeforeParentDelete(); + } + ~WebEngineQuickWidget() override + { + if (m_contentItem) { + m_contentItem->setWidgetDelegate(nullptr); + m_contentItem->setParentItem(nullptr); + } + } + + void InitAsPopup(const QRect &screenRect) override + { + setAttribute(Qt::WA_ShowWithoutActivating); + setFocusPolicy(Qt::NoFocus); + setWindowFlags(Qt::Popup | Qt::FramelessWindowHint | Qt::WindowDoesNotAcceptFocus); + + setGeometry(screenRect); + raise(); + m_contentItem->show(); + show(); + } + + void Bind(WebContentsAdapterClient *client) override + { + if (m_pageDestroyedConnection) + QObject::disconnect(m_pageDestroyedConnection); + QWebEnginePage *page = static_cast<QWebEnginePagePrivate *>(client)->q_func(); + QWebEngineViewPrivate::bindPageAndWidget(page, this); + m_pageDestroyedConnection = QObject::connect(page, &QWebEnginePage::_q_aboutToDelete, this, &WebEngineQuickWidget::Unbind); + } + + void Unbind() override + { + if (m_pageDestroyedConnection) + QObject::disconnect(m_pageDestroyedConnection); + QWebEngineViewPrivate::bindPageAndWidget(nullptr, this); + } + + void Destroy() override + { + deleteLater(); + } + + bool ActiveFocusOnPress() override + { + return true; + } + + void SetInputMethodEnabled(bool enabled) override + { + QQuickWidget::setAttribute(Qt::WA_InputMethodEnabled, enabled); + } + void SetInputMethodHints(Qt::InputMethodHints hints) override + { + QQuickWidget::setInputMethodHints(hints); + } + void SetClearColor(const QColor &color) override + { + QQuickWidget::setClearColor(color); + // QQuickWidget is usually blended by punching holes into widgets + // above it to simulate the visual stacking order. If we want it to be + // transparent we have to throw away the proper stacking order and always + // blend the complete normal widgets backing store under it. + bool isTranslucent = color.alpha() < 255; + setAttribute(Qt::WA_AlwaysStackOnTop, isTranslucent); + setAttribute(Qt::WA_OpaquePaintEvent, !isTranslucent); + update(); + } + void MoveWindow(const QPoint &screenPos) override + { + QQuickWidget::move(screenPos); + } + void Resize(int width, int height) override + { + QQuickWidget::resize(width, height); + } + QWindow *Window() override + { + if (const QWidget *root = QQuickWidget::window()) + return root->windowHandle(); + return nullptr; + } + +protected: + void closeEvent(QCloseEvent *event) override + { + QQuickWidget::closeEvent(event); + + // If a close event was received from the window manager (e.g. when moving the parent window, + // clicking outside the popup area) + // make sure to notify the Chromium WebUI popup and its underlying + // RenderWidgetHostViewQtDelegate instance to be closed. + if (m_contentItem && m_contentItem->m_isPopup) + m_contentItem->m_client->closePopup(); + } + void showEvent(QShowEvent *event) override + { + QQuickWidget::showEvent(event); + // We don't have a way to catch a top-level window change with QWidget + // but a widget will most likely be shown again if it changes, so do + // the reconnection at this point. + for (const QMetaObject::Connection &c : qAsConst(m_windowConnections)) + disconnect(c); + m_windowConnections.clear(); + if (QWindow *w = Window()) { + m_windowConnections.append(connect(w, SIGNAL(xChanged(int)), m_contentItem, SLOT(onWindowPosChanged()))); + m_windowConnections.append(connect(w, SIGNAL(yChanged(int)), m_contentItem, SLOT(onWindowPosChanged()))); + } + } + void resizeEvent(QResizeEvent *event) override + { + QQuickWidget::resizeEvent(event); + if (m_contentItem) { // FIXME: Not sure why we need to set m_contentItem size manually + m_contentItem->setSize(event->size()); + m_contentItem->onWindowPosChanged(); + } + } + QVariant inputMethodQuery(Qt::InputMethodQuery query) const override + { + if (m_contentItem) + return m_contentItem->inputMethodQuery(query); + return QVariant(); + } + bool event(QEvent *event) override; + + void connectRemoveParentBeforeParentDelete(); + void removeParentBeforeParentDelete(); + +private: + friend QWebEngineViewPrivate; + QPointer<RenderWidgetHostViewQtDelegateItem> m_contentItem; // deleted by core + QMetaObject::Connection m_parentDestroyedConnection; + QMetaObject::Connection m_pageDestroyedConnection; + QList<QMetaObject::Connection> m_windowConnections; +}; + +void WebEngineQuickWidget::connectRemoveParentBeforeParentDelete() +{ + disconnect(m_parentDestroyedConnection); + + if (QWidget *parent = parentWidget()) { + m_parentDestroyedConnection = connect(parent, &QObject::destroyed, + this, + &WebEngineQuickWidget::removeParentBeforeParentDelete); + } else { + m_parentDestroyedConnection = QMetaObject::Connection(); + } +} + +void WebEngineQuickWidget::removeParentBeforeParentDelete() +{ + // Unset the parent, because parent is being destroyed, but the owner of this + // WebEngineQuickWidget is actually a RenderWidgetHostViewQt instance. + setParent(nullptr); + + // If this widget represents a popup window, make sure to close it, so that if the popup was the + // last visible top level window, the application event loop can quit if it deems it necessarry. + if (m_contentItem && m_contentItem->m_isPopup) + close(); +} + +bool WebEngineQuickWidget::event(QEvent *event) +{ + bool handled = false; + + // Track parent to make sure we don't get deleted. + if (event->type() == QEvent::ParentChange) + connectRemoveParentBeforeParentDelete(); + + if (!m_contentItem) + return QQuickWidget::event(event); + + // Mimic QWidget::event() by ignoring mouse, keyboard, touch and tablet events if the widget is + // disabled. + if (!isEnabled()) { + switch (event->type()) { + case QEvent::TabletPress: + case QEvent::TabletRelease: + case QEvent::TabletMove: + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + case QEvent::MouseButtonDblClick: + case QEvent::MouseMove: + case QEvent::TouchBegin: + case QEvent::TouchUpdate: + case QEvent::TouchEnd: + case QEvent::TouchCancel: + case QEvent::ContextMenu: + case QEvent::KeyPress: + case QEvent::KeyRelease: +#ifndef QT_NO_WHEELEVENT + case QEvent::Wheel: +#endif + return false; + default: + break; + } + } + + switch (event->type()) { + case QEvent::FocusIn: + case QEvent::FocusOut: + // We forward focus events later, once they have made it to the content item. + return QQuickWidget::event(event); + case QEvent::DragEnter: + case QEvent::DragLeave: + case QEvent::DragMove: + case QEvent::Drop: + case QEvent::HoverEnter: + case QEvent::HoverLeave: + case QEvent::HoverMove: + // Let the parent handle these events. + return false; + default: + break; + } + + switch (event->type()) { + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + case QEvent::MouseButtonDblClick: + case QEvent::MouseMove: + // 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. + // Only allow them for popup type, since QWidgetWindow will ignore them for Qt::Popup flag, + // which is expected to get input through synthesized mouse events (either by system or Qt) + if (!m_contentItem->m_isPopup && + static_cast<QMouseEvent *>(event)->source() == Qt::MouseEventSynthesizedBySystem) { + Q_ASSERT(!windowFlags().testFlag(Qt::Popup)); + return true; + } + break; + default: + break; + } + + if (event->type() == QEvent::MouseButtonDblClick) { + // QWidget keeps the Qt4 behavior where the DblClick event would replace the Press event. + // QtQuick is different by sending both the Press and DblClick events for the second press + // where we can simply ignore the DblClick event. + QMouseEvent *dblClick = static_cast<QMouseEvent *>(event); + QMouseEvent press(QEvent::MouseButtonPress, dblClick->position(), dblClick->scenePosition(), + dblClick->globalPosition(), dblClick->button(), dblClick->buttons(), + dblClick->modifiers(), dblClick->source()); + press.setTimestamp(dblClick->timestamp()); + handled = m_contentItem->m_client->forwardEvent(&press); + } else + handled = m_contentItem->m_client->forwardEvent(event); + + if (!handled) + return QQuickWidget::event(event); + event->accept(); + return true; +} + +} // namespace QtWebEngineCore + QT_BEGIN_NAMESPACE void QWebEngineViewPrivate::pageChanged(QWebEnginePage *oldPage, QWebEnginePage *newPage) @@ -144,8 +427,8 @@ void QWebEngineViewPrivate::pageChanged(QWebEnginePage *oldPage, QWebEnginePage Q_EMIT q->selectionChanged(); } -void QWebEngineViewPrivate::widgetChanged(QtWebEngineCore::RenderWidgetHostViewQtDelegateWidget *oldWidget, - QtWebEngineCore::RenderWidgetHostViewQtDelegateWidget *newWidget) +void QWebEngineViewPrivate::widgetChanged(QtWebEngineCore::WebEngineQuickWidget *oldWidget, + QtWebEngineCore::WebEngineQuickWidget *newWidget) { Q_Q(QWebEngineView); @@ -162,8 +445,6 @@ void QWebEngineViewPrivate::widgetChanged(QtWebEngineCore::RenderWidgetHostViewQ if (newWidget) { Q_ASSERT(!QtWebEngineCore::closingDown()); #if QT_CONFIG(accessibility) - // An earlier QAccessible::queryAccessibleInterface() call may have already registered a default - // QAccessibleInterface for newWidget: remove it first to avoid assert in QAccessibleCache::insert(). QAccessible::deleteAccessibleInterface(QAccessible::uniqueId(QAccessible::queryAccessibleInterface(newWidget))); QAccessible::registerAccessibleInterface(new QtWebEngineCore::RenderWidgetHostViewQtDelegateWidgetAccessible(newWidget, q)); #endif @@ -403,20 +684,24 @@ void QWebEngineViewPrivate::bindPageAndView(QWebEnginePage *page, QWebEngineView // Then notify. - auto widget = page ? page->d_func()->widget : nullptr; - auto oldWidget = (oldPage && oldPage->d_func()) ? oldPage->d_func()->widget : nullptr; + auto widget = page ? static_cast<QtWebEngineCore::WebEngineQuickWidget *>(page->d_func()->widget) : nullptr; + auto oldWidget = (oldPage && oldPage->d_func()) ? static_cast<QtWebEngineCore::WebEngineQuickWidget *>(oldPage->d_func()->widget) : nullptr; + // New page/widget moving away from oldView if (page && oldView != view && oldView) { oldView->d_func()->pageChanged(page, nullptr); if (widget) oldView->d_func()->widgetChanged(widget, nullptr); } + // New page/widget moving into new view if (view && oldPage != page) { if (oldPage && oldPage->d_func()) view->d_func()->pageChanged(oldPage, page); else view->d_func()->pageChanged(nullptr, page); + if (!widget && page && page->d_func()->item) + widget = new QtWebEngineCore::WebEngineQuickWidget(page->d_func()->item, nullptr); if (oldWidget != widget) view->d_func()->widgetChanged(oldWidget, widget); } @@ -425,23 +710,27 @@ void QWebEngineViewPrivate::bindPageAndView(QWebEnginePage *page, QWebEngineView } void QWebEngineViewPrivate::bindPageAndWidget( - QWebEnginePage *page, QtWebEngineCore::RenderWidgetHostViewQtDelegateWidget *widget) + QWebEnginePage *page, QtWebEngineCore::WebEngineQuickWidget *widget) { - auto oldPage = widget ? widget->m_page : nullptr; - auto oldWidget = page ? page->d_func()->widget : nullptr; + auto oldPage = (widget && widget->m_contentItem) ? widget->m_contentItem->m_page : nullptr; + auto oldWidget = page ? static_cast<QtWebEngineCore::WebEngineQuickWidget *>(page->d_func()->widget) : nullptr; // Change pointers first. if (widget && oldPage != page) { - if (oldPage && oldPage->d_func()) + if (oldPage && oldPage->d_func()) { oldPage->d_func()->widget = nullptr; - widget->m_page = page; + oldPage->d_func()->item = nullptr; + } + if (widget->m_contentItem) + widget->m_contentItem->m_page = page; } if (page && oldWidget != widget) { - if (oldWidget) - oldWidget->m_page = nullptr; + if (oldWidget && oldWidget->m_contentItem) + oldWidget->m_contentItem->m_page = nullptr; page->d_func()->widget = widget; + page->d_func()->item = widget->m_contentItem; } // Then notify. @@ -585,8 +874,21 @@ QtWebEngineCore::RenderWidgetHostViewQtDelegate * QWebEngineViewPrivate::CreateRenderWidgetHostViewQtDelegate( QtWebEngineCore::RenderWidgetHostViewQtDelegateClient *client) { + auto *item = new QtWebEngineCore::RenderWidgetHostViewQtDelegateItem(client, false); + auto *widget = new QtWebEngineCore::WebEngineQuickWidget(item, nullptr); + item->setWidgetDelegate(widget); + return item; +} + +QtWebEngineCore::RenderWidgetHostViewQtDelegate * +QWebEngineViewPrivate::CreateRenderWidgetHostViewQtDelegateForPopup( + QtWebEngineCore::RenderWidgetHostViewQtDelegateClient *client) +{ Q_Q(QWebEngineView); - return new QtWebEngineCore::RenderWidgetHostViewQtDelegateWidget(client, q); + auto *item = new QtWebEngineCore::RenderWidgetHostViewQtDelegateItem(client, true); + auto *widget = new QtWebEngineCore::WebEngineQuickWidget(item, q); + item->setWidgetDelegate(widget); + return item; } QWebEngineContextMenuRequest *QWebEngineViewPrivate::lastContextMenuRequest() const @@ -1115,45 +1417,6 @@ void QWebEngineView::print(QPrinter *printer) #endif } -#ifndef QT_NO_ACCESSIBILITY -bool QWebEngineViewAccessible::isValid() const -{ - if (!QAccessibleWidget::isValid()) - return false; - - if (!view() || !view()->d_func() || !view()->d_func()->page || !view()->d_func()->page->d_func()) - return false; - - return true; -} - -QAccessibleInterface *QWebEngineViewAccessible::focusChild() const -{ - if (child(0) && child(0)->focusChild()) - return child(0)->focusChild(); - return const_cast<QWebEngineViewAccessible *>(this); -} - -int QWebEngineViewAccessible::childCount() const -{ - return child(0) ? 1 : 0; -} - -QAccessibleInterface *QWebEngineViewAccessible::child(int index) const -{ - if (index == 0 && isValid()) - return view()->page()->d_func()->adapter->browserAccessible(); - return nullptr; -} - -int QWebEngineViewAccessible::indexOfChild(const QAccessibleInterface *c) const -{ - if (child(0) && c == child(0)) - return 0; - return -1; -} -#endif // QT_NO_ACCESSIBILITY - #if QT_CONFIG(action) QContextMenuBuilder::QContextMenuBuilder(QWebEngineContextMenuRequest *request, QWebEngineView *view, QMenu *menu) diff --git a/src/webenginewidgets/api/qwebengineview_p.h b/src/webenginewidgets/api/qwebengineview_p.h index b5d38a6c1..e3c9468ce 100644 --- a/src/webenginewidgets/api/qwebengineview_p.h +++ b/src/webenginewidgets/api/qwebengineview_p.h @@ -52,14 +52,14 @@ // #include <QtWebEngineCore/private/qwebenginepage_p.h> // PageView -#include <QtWidgets/qaccessiblewidget.h> #include "render_view_context_menu_qt.h" namespace QtWebEngineCore { class QWebEngineContextMenuRequest; -class RenderWidgetHostViewQtDelegateWidget; +class WebEngineQuickWidget; class RenderWidgetHostViewQtDelegate; +class RenderWidgetHostViewQtDelegateClient; } QT_BEGIN_NAMESPACE @@ -75,8 +75,8 @@ public: QWebEngineView *q_ptr; void pageChanged(QWebEnginePage *oldPage, QWebEnginePage *newPage); - void widgetChanged(QtWebEngineCore::RenderWidgetHostViewQtDelegateWidget *oldWidget, - QtWebEngineCore::RenderWidgetHostViewQtDelegateWidget *newWidget); + void widgetChanged(QtWebEngineCore::WebEngineQuickWidget *oldWidget, + QtWebEngineCore::WebEngineQuickWidget *newWidget); void contextMenuRequested(QWebEngineContextMenuRequest *request) override; QStringList chooseFiles(QWebEnginePage::FileSelectionMode mode, const QStringList &oldFiles, @@ -91,6 +91,8 @@ public: void setToolTip(const QString &toolTipText) override; QtWebEngineCore::RenderWidgetHostViewQtDelegate *CreateRenderWidgetHostViewQtDelegate( QtWebEngineCore::RenderWidgetHostViewQtDelegateClient *client) override; + QtWebEngineCore::RenderWidgetHostViewQtDelegate *CreateRenderWidgetHostViewQtDelegateForPopup( + QtWebEngineCore::RenderWidgetHostViewQtDelegateClient *client) override; QWebEngineContextMenuRequest *lastContextMenuRequest() const override; QWebEnginePage *createPageForWindow(QWebEnginePage::WebWindowType type) override; QObject *accessibilityParentObject() override; @@ -102,7 +104,7 @@ public: virtual ~QWebEngineViewPrivate(); static void bindPageAndView(QWebEnginePage *page, QWebEngineView *view); static void bindPageAndWidget(QWebEnginePage *page, - QtWebEngineCore::RenderWidgetHostViewQtDelegateWidget *widget); + QtWebEngineCore::WebEngineQuickWidget *widget); QIcon webActionIcon(QWebEnginePage::WebAction action); void unhandledKeyEvent(QKeyEvent *event) override; void focusContainer() override; @@ -117,24 +119,6 @@ public: QWebEngineContextMenuRequest *m_contextRequest; }; -#ifndef QT_NO_ACCESSIBILITY -class QWebEngineViewAccessible : public QAccessibleWidget -{ -public: - QWebEngineViewAccessible(QWebEngineView *o) : QAccessibleWidget(o) - {} - - bool isValid() const override; - QAccessibleInterface *focusChild() const override; - int childCount() const override; - QAccessibleInterface *child(int index) const override; - int indexOfChild(const QAccessibleInterface *child) const override; - -private: - QWebEngineView *view() const { return static_cast<QWebEngineView *>(object()); } -}; -#endif // QT_NO_ACCESSIBILITY - class QContextMenuBuilder : public QtWebEngineCore::RenderViewContextMenuQt { public: diff --git a/src/webenginewidgets/qwebengine_accessible.cpp b/src/webenginewidgets/qwebengine_accessible.cpp new file mode 100644 index 000000000..a1b4bc889 --- /dev/null +++ b/src/webenginewidgets/qwebengine_accessible.cpp @@ -0,0 +1,142 @@ +/**************************************************************************** +** +** 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 "qwebengine_accessible.h" + +#include "qwebengineview.h" +#include "qwebengineview_p.h" + +#include "web_contents_adapter.h" + +#if QT_CONFIG(accessibility) + +QT_BEGIN_NAMESPACE + +QWebEngineViewAccessible::QWebEngineViewAccessible(QWebEngineView *o) : QAccessibleWidget(o) +{ +} + +bool QWebEngineViewAccessible::isValid() const +{ + if (!QAccessibleWidget::isValid()) + return false; + + if (!view() || !view()->d_func() || !view()->d_func()->page || !view()->d_func()->page->d_func()) + return false; + + return true; +} + +QAccessibleInterface *QWebEngineViewAccessible::focusChild() const +{ + if (child(0) && child(0)->focusChild()) + return child(0)->focusChild(); + return const_cast<QWebEngineViewAccessible *>(this); +} + +int QWebEngineViewAccessible::childCount() const +{ + return child(0) ? 1 : 0; +} + +QAccessibleInterface *QWebEngineViewAccessible::child(int index) const +{ + if (index == 0 && isValid()) + return view()->page()->d_func()->adapter->browserAccessible(); + return nullptr; +} + +int QWebEngineViewAccessible::indexOfChild(const QAccessibleInterface *c) const +{ + if (child(0) && c == child(0)) + return 0; + return -1; +} + +QWebEngineView *QWebEngineViewAccessible::view() const +{ + return static_cast<QWebEngineView *>(object()); +} + +QT_END_NAMESPACE + +namespace QtWebEngineCore { + +RenderWidgetHostViewQtDelegateWidgetAccessible::RenderWidgetHostViewQtDelegateWidgetAccessible(QWidget *o, QWebEngineView *view) + : QAccessibleWidget(o) + , m_view(view) +{ +} + +bool RenderWidgetHostViewQtDelegateWidgetAccessible::isValid() const +{ + if (!viewAccessible() || !viewAccessible()->isValid()) + return false; + + return QAccessibleWidget::isValid(); +} + +QAccessibleInterface *RenderWidgetHostViewQtDelegateWidgetAccessible::focusChild() const +{ + return viewAccessible()->focusChild(); +} + +int RenderWidgetHostViewQtDelegateWidgetAccessible::childCount() const +{ + return viewAccessible()->childCount(); +} + +QAccessibleInterface *RenderWidgetHostViewQtDelegateWidgetAccessible::child(int index) const +{ + return viewAccessible()->child(index); +} + +int RenderWidgetHostViewQtDelegateWidgetAccessible::indexOfChild(const QAccessibleInterface *c) const +{ + return viewAccessible()->indexOfChild(c); +} + +QWebEngineViewAccessible *RenderWidgetHostViewQtDelegateWidgetAccessible::viewAccessible() const +{ + return static_cast<QWebEngineViewAccessible *>(QAccessible::queryAccessibleInterface(m_view)); +} + +} // namespace QtWebEngineCore + +#endif // QT_CONFIG(accessibility) diff --git a/src/webenginewidgets/qwebengine_accessible.h b/src/webenginewidgets/qwebengine_accessible.h new file mode 100644 index 000000000..d0781635d --- /dev/null +++ b/src/webenginewidgets/qwebengine_accessible.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** 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 QWEBENGINE_ACCESSIBLE_H +#define QWEBENGINE_ACCESSIBLE_H + +#include <QAccessibleWidget> +#include <QPointer> + +#if QT_CONFIG(accessibility) + +QT_BEGIN_NAMESPACE +class QWebEngineView; + +class QWebEngineViewAccessible : public QAccessibleWidget +{ +public: + QWebEngineViewAccessible(QWebEngineView *o); + + bool isValid() const override; + QAccessibleInterface *focusChild() const override; + int childCount() const override; + QAccessibleInterface *child(int index) const override; + int indexOfChild(const QAccessibleInterface *child) const override; + +private: + QWebEngineView *view() const; +}; + +QT_END_NAMESPACE + +namespace QtWebEngineCore { + +class RenderWidgetHostViewQtDelegateWidgetAccessible : public QAccessibleWidget +{ +public: + RenderWidgetHostViewQtDelegateWidgetAccessible(QWidget *o, QWebEngineView *view); + + bool isValid() const override; + QAccessibleInterface *focusChild() const override; + int childCount() const override; + QAccessibleInterface *child(int index) const override; + int indexOfChild(const QAccessibleInterface *child) const override; + +private: + QWebEngineViewAccessible *viewAccessible() const; + QPointer<QWebEngineView> m_view; +}; +} // namespace QtWebEngineCore +#endif // QT_CONFIG(accessibility) + +#endif // QWEBENGINE_ACCESSIBLE_H diff --git a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp deleted file mode 100644 index 1dd19fd67..000000000 --- a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp +++ /dev/null @@ -1,542 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtWebEngine module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "render_widget_host_view_qt_delegate_widget.h" - -#include "render_widget_host_view_qt_delegate_client.h" - -#include <QtWebEngineCore/private/qwebenginepage_p.h> -#include "qwebengineview.h" -#include "qwebengineview_p.h" - -#include <QGuiApplication> -#include <QMouseEvent> -#include <QResizeEvent> -#include <QSGImageNode> -#include <QWindow> - -namespace QtWebEngineCore { - -class RenderWidgetHostViewQuickItem : public QQuickItem, public Compositor::Observer -{ -public: - RenderWidgetHostViewQuickItem(RenderWidgetHostViewQtDelegateClient *client) : m_client(client) - { - setFlag(ItemHasContents, true); - // Mark that this item should receive focus when the parent QQuickWidget receives focus. - setFocus(true); - - bind(client->compositorId()); - } - -protected: - bool event(QEvent *event) override - { - if (event->type() == QEvent::ShortcutOverride) - return m_client->forwardEvent(event); - - return QQuickItem::event(event); - } - void focusInEvent(QFocusEvent *event) override - { - m_client->forwardEvent(event); - } - void focusOutEvent(QFocusEvent *event) override - { - m_client->forwardEvent(event); - } - void inputMethodEvent(QInputMethodEvent *event) override - { - m_client->forwardEvent(event); - } - void itemChange(ItemChange change, const ItemChangeData &value) override - { - QQuickItem::itemChange(change, value); - if (change == QQuickItem::ItemSceneChange) { - for (const QMetaObject::Connection &c : qAsConst(m_windowConnections)) - disconnect(c); - m_windowConnections.clear(); - if (value.window) { - m_windowConnections.append(connect( - value.window, &QQuickWindow::beforeRendering, this, - &RenderWidgetHostViewQuickItem::onBeforeRendering, Qt::DirectConnection)); - } - } - } - QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) override - { - auto comp = compositor(); - if (!comp) - return nullptr; - - QQuickWindow *win = QQuickItem::window(); - - // Delete old node before swapFrame to decrement refcount of - // QImage in software mode. - delete oldNode; - QSGImageNode *node = win->createImageNode(); - node->setOwnsTexture(true); - - comp->swapFrame(); - - QSize texSize = comp->size(); - QSizeF texSizeInDips = QSizeF(texSize) / comp->devicePixelRatio(); - node->setRect(QRectF(QPointF(0, 0), texSizeInDips)); - - if (comp->type() == Compositor::Type::Software) { - QImage image = comp->image(); - node->setTexture(win->createTextureFromImage(image)); - } else if (comp->type() == Compositor::Type::OpenGL) { -#if QT_CONFIG(opengl) - QQuickWindow::CreateTextureOptions texOpts; - if (comp->hasAlphaChannel()) - texOpts.setFlag(QQuickWindow::TextureHasAlphaChannel); - int texId = comp->textureId(); - node->setTexture(QNativeInterface::QSGOpenGLTexture::fromNative(texId, win, texSize, texOpts)); - node->setTextureCoordinatesTransform(QSGImageNode::MirrorVertically); -#else - Q_UNREACHABLE(); - -#endif - } else { - Q_UNREACHABLE(); - } - - return node; - } - void onBeforeRendering() - { - auto comp = compositor(); - if (!comp || comp->type() != Compositor::Type::OpenGL) - return; - comp->waitForTexture(); - } - QVariant inputMethodQuery(Qt::InputMethodQuery query) const override - { - return m_client->inputMethodQuery(query); - } - void readyToSwap() override - { - // Call update() on UI thread. - QMetaObject::invokeMethod(this, &QQuickItem::update, Qt::QueuedConnection); - } - -private: - RenderWidgetHostViewQtDelegateClient *m_client; - QList<QMetaObject::Connection> m_windowConnections; -}; - -RenderWidgetHostViewQtDelegateWidget::RenderWidgetHostViewQtDelegateWidget(RenderWidgetHostViewQtDelegateClient *client, QWidget *parent) - : QQuickWidget(parent) - , m_client(client) - , m_rootItem(new RenderWidgetHostViewQuickItem(client)) - , m_isPopup(false) -{ - setFocusPolicy(Qt::StrongFocus); - setMouseTracking(true); - setAttribute(Qt::WA_AcceptTouchEvents); - setAttribute(Qt::WA_OpaquePaintEvent); - setAttribute(Qt::WA_AlwaysShowToolTips); - - setContent(QUrl(), nullptr, m_rootItem.data()); - - connectRemoveParentBeforeParentDelete(); -} - -RenderWidgetHostViewQtDelegateWidget::~RenderWidgetHostViewQtDelegateWidget() -{ - QWebEngineViewPrivate::bindPageAndWidget(nullptr, this); -} - -void RenderWidgetHostViewQtDelegateWidget::connectRemoveParentBeforeParentDelete() -{ - disconnect(m_parentDestroyedConnection); - - if (QWidget *parent = parentWidget()) { - m_parentDestroyedConnection = connect(parent, &QObject::destroyed, - this, - &RenderWidgetHostViewQtDelegateWidget::removeParentBeforeParentDelete); - } else { - m_parentDestroyedConnection = QMetaObject::Connection(); - } -} - -void RenderWidgetHostViewQtDelegateWidget::removeParentBeforeParentDelete() -{ - // Unset the parent, because parent is being destroyed, but the owner of this - // RenderWidgetHostViewQtDelegateWidget is actually a RenderWidgetHostViewQt instance. - setParent(nullptr); - - // If this widget represents a popup window, make sure to close it, so that if the popup was the - // last visible top level window, the application event loop can quit if it deems it necessarry. - if (m_isPopup) - close(); -} - -void RenderWidgetHostViewQtDelegateWidget::initAsPopup(const QRect& screenRect) -{ - m_isPopup = true; - - // The keyboard events are supposed to go to the parent RenderHostView - // so the WebUI popups should never have focus. Besides, if the parent view - // loses focus, WebKit will cause its associated popups (including this one) - // to be destroyed. - setAttribute(Qt::WA_ShowWithoutActivating); - setFocusPolicy(Qt::NoFocus); - setWindowFlags(Qt::Popup | Qt::FramelessWindowHint | Qt::WindowDoesNotAcceptFocus); - - setGeometry(screenRect); - show(); -} - -void RenderWidgetHostViewQtDelegateWidget::closeEvent(QCloseEvent *event) -{ - Q_UNUSED(event); - - // If a close event was received from the window manager (e.g. when moving the parent window, - // clicking outside the popup area) - // make sure to notify the Chromium WebUI popup and its underlying - // RenderWidgetHostViewQtDelegate instance to be closed. - if (m_isPopup) - m_client->closePopup(); -} - -QRectF RenderWidgetHostViewQtDelegateWidget::viewGeometry() const -{ - return QRectF(mapToGlobal(pos()), size()); -} - -QRect RenderWidgetHostViewQtDelegateWidget::windowGeometry() const -{ - if (!window()) - return QRect(); - return window()->frameGeometry(); -} - -void RenderWidgetHostViewQtDelegateWidget::setKeyboardFocus() -{ - // The root item always has focus within the root focus scope: - Q_ASSERT(m_rootItem->hasFocus()); - - setFocus(); -} - -bool RenderWidgetHostViewQtDelegateWidget::hasKeyboardFocus() -{ - // The root item always has focus within the root focus scope: - Q_ASSERT(m_rootItem->hasFocus()); - - return hasFocus(); -} - -void RenderWidgetHostViewQtDelegateWidget::lockMouse() -{ - grabMouse(); -} - -void RenderWidgetHostViewQtDelegateWidget::unlockMouse() -{ - releaseMouse(); -} - -void RenderWidgetHostViewQtDelegateWidget::show() -{ - m_rootItem->setVisible(true); - // Check if we're attached to a QWebEngineView, we don't - // want to show anything else than popups as top-level. - if (parent() || m_isPopup) { - QQuickWidget::show(); - } -} - -void RenderWidgetHostViewQtDelegateWidget::hide() -{ - m_rootItem->setVisible(false); - QQuickWidget::hide(); -} - -bool RenderWidgetHostViewQtDelegateWidget::isVisible() const -{ - return QQuickWidget::isVisible() && m_rootItem->isVisible(); -} - -QWindow* RenderWidgetHostViewQtDelegateWidget::window() const -{ - const QWidget* root = QQuickWidget::window(); - return root ? root->windowHandle() : 0; -} - -void RenderWidgetHostViewQtDelegateWidget::updateCursor(const QCursor &cursor) -{ - QQuickWidget::setCursor(cursor); -} - -void RenderWidgetHostViewQtDelegateWidget::resize(int width, int height) -{ - QQuickWidget::resize(width, height); -} - -void RenderWidgetHostViewQtDelegateWidget::move(const QPoint &screenPos) -{ - Q_ASSERT(m_isPopup); - QQuickWidget::move(screenPos); -} - -void RenderWidgetHostViewQtDelegateWidget::inputMethodStateChanged(bool editorVisible, bool passwordInput) -{ - QQuickWidget::setAttribute(Qt::WA_InputMethodEnabled, editorVisible && !passwordInput); - qApp->inputMethod()->update(Qt::ImQueryInput | Qt::ImEnabled | Qt::ImHints); - if (qApp->inputMethod()->isVisible() != editorVisible) - qApp->inputMethod()->setVisible(editorVisible); -} - -void RenderWidgetHostViewQtDelegateWidget::setInputMethodHints(Qt::InputMethodHints hints) -{ - QQuickWidget::setInputMethodHints(hints); -} - -void RenderWidgetHostViewQtDelegateWidget::setClearColor(const QColor &color) -{ - QQuickWidget::setClearColor(color); - // QQuickWidget is usually blended by punching holes into widgets - // above it to simulate the visual stacking order. If we want it to be - // transparent we have to throw away the proper stacking order and always - // blend the complete normal widgets backing store under it. - bool isTranslucent = color.alpha() < 255; - setAttribute(Qt::WA_AlwaysStackOnTop, isTranslucent); - setAttribute(Qt::WA_OpaquePaintEvent, !isTranslucent); - update(); -} - -QVariant RenderWidgetHostViewQtDelegateWidget::inputMethodQuery(Qt::InputMethodQuery query) const -{ - return m_client->inputMethodQuery(query); -} - -void RenderWidgetHostViewQtDelegateWidget::resizeEvent(QResizeEvent *resizeEvent) -{ - QQuickWidget::resizeEvent(resizeEvent); - m_client->visualPropertiesChanged(); -} - -void RenderWidgetHostViewQtDelegateWidget::showEvent(QShowEvent *event) -{ - QQuickWidget::showEvent(event); - // We don't have a way to catch a top-level window change with QWidget - // but a widget will most likely be shown again if it changes, so do - // the reconnection at this point. - for (const QMetaObject::Connection &c : qAsConst(m_windowConnections)) - disconnect(c); - m_windowConnections.clear(); - if (QWindow *w = window()) { - m_windowConnections.append(connect(w, SIGNAL(xChanged(int)), SLOT(onWindowPosChanged()))); - m_windowConnections.append(connect(w, SIGNAL(yChanged(int)), SLOT(onWindowPosChanged()))); - } - m_client->visualPropertiesChanged(); - m_client->notifyShown(); -} - -void RenderWidgetHostViewQtDelegateWidget::hideEvent(QHideEvent *event) -{ - QQuickWidget::hideEvent(event); - m_client->notifyHidden(); -} - -bool RenderWidgetHostViewQtDelegateWidget::event(QEvent *event) -{ - bool handled = false; - - // Track parent to make sure we don't get deleted. - switch (event->type()) { - case QEvent::ParentChange: - connectRemoveParentBeforeParentDelete(); - break; - default: - break; - } - - // Mimic QWidget::event() by ignoring mouse, keyboard, touch and tablet events if the widget is - // disabled. - if (!isEnabled()) { - switch (event->type()) { - case QEvent::TabletPress: - case QEvent::TabletRelease: - case QEvent::TabletMove: - case QEvent::MouseButtonPress: - case QEvent::MouseButtonRelease: - case QEvent::MouseButtonDblClick: - case QEvent::MouseMove: - case QEvent::TouchBegin: - case QEvent::TouchUpdate: - case QEvent::TouchEnd: - case QEvent::TouchCancel: - case QEvent::ContextMenu: - case QEvent::KeyPress: - case QEvent::KeyRelease: -#ifndef QT_NO_WHEELEVENT - case QEvent::Wheel: -#endif - return false; - default: - break; - } - } - - switch (event->type()) { - case QEvent::FocusIn: - case QEvent::FocusOut: - // We forward focus events later, once they have made it to the m_rootItem. - return QQuickWidget::event(event); - case QEvent::DragEnter: - case QEvent::DragLeave: - case QEvent::DragMove: - case QEvent::Drop: - case QEvent::HoverEnter: - case QEvent::HoverLeave: - case QEvent::HoverMove: - // Let the parent handle these events. - return false; - default: - break; - } - - switch (event->type()) { - case QEvent::MouseButtonPress: - case QEvent::MouseButtonRelease: - case QEvent::MouseButtonDblClick: - case QEvent::MouseMove: - // 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. - // Only allow them for popup type, since QWidgetWindow will ignore them for Qt::Popup flag, - // which is expected to get input through synthesized mouse events (either by system or Qt) - if (!m_isPopup && static_cast<QMouseEvent *>(event)->source() == Qt::MouseEventSynthesizedBySystem) { - Q_ASSERT(!windowFlags().testFlag(Qt::Popup)); - return true; - } - break; - default: - break; - } - - if (event->type() == QEvent::MouseButtonDblClick) { - // QWidget keeps the Qt4 behavior where the DblClick event would replace the Press event. - // QtQuick is different by sending both the Press and DblClick events for the second press - // where we can simply ignore the DblClick event. - QMouseEvent *dblClick = static_cast<QMouseEvent *>(event); - QMouseEvent press(QEvent::MouseButtonPress, dblClick->position(), dblClick->scenePosition(), - dblClick->globalPosition(), dblClick->button(), dblClick->buttons(), - dblClick->modifiers(), dblClick->source()); - press.setTimestamp(dblClick->timestamp()); - handled = m_client->forwardEvent(&press); - } else - handled = m_client->forwardEvent(event); - - if (!handled) - return QQuickWidget::event(event); - event->accept(); - return true; -} - -void RenderWidgetHostViewQtDelegateWidget::unhandledWheelEvent(QWheelEvent *ev) -{ - if (QWidget *p = parentWidget()) - qApp->sendEvent(p, ev); -} - -void RenderWidgetHostViewQtDelegateWidget::onWindowPosChanged() -{ - m_client->visualPropertiesChanged(); -} - -void RenderWidgetHostViewQtDelegateWidget::adapterClientChanged(WebContentsAdapterClient *client) -{ - if (m_pageDestroyedConnection) - disconnect(m_pageDestroyedConnection); - QWebEnginePage *page = static_cast<QWebEnginePagePrivate *>(client)->q_func(); - QWebEngineViewPrivate::bindPageAndWidget(page, this); - m_pageDestroyedConnection = connect(page, &QWebEnginePage::_q_aboutToDelete, this, - [this]() { QWebEngineViewPrivate::bindPageAndWidget(nullptr, this); }); -} - -#if QT_CONFIG(accessibility) -RenderWidgetHostViewQtDelegateWidgetAccessible::RenderWidgetHostViewQtDelegateWidgetAccessible(RenderWidgetHostViewQtDelegateWidget *o, QWebEngineView *view) - : QAccessibleWidget(o) - , m_view(view) -{ -} - -bool RenderWidgetHostViewQtDelegateWidgetAccessible::isValid() const -{ - if (!viewAccessible() || !viewAccessible()->isValid()) - return false; - - return QAccessibleWidget::isValid(); -} - -QAccessibleInterface *RenderWidgetHostViewQtDelegateWidgetAccessible::focusChild() const -{ - return viewAccessible()->focusChild(); -} - -int RenderWidgetHostViewQtDelegateWidgetAccessible::childCount() const -{ - return viewAccessible()->childCount(); -} - -QAccessibleInterface *RenderWidgetHostViewQtDelegateWidgetAccessible::child(int index) const -{ - return viewAccessible()->child(index); -} - -int RenderWidgetHostViewQtDelegateWidgetAccessible::indexOfChild(const QAccessibleInterface *c) const -{ - return viewAccessible()->indexOfChild(c); -} - -QWebEngineViewAccessible *RenderWidgetHostViewQtDelegateWidgetAccessible::viewAccessible() const -{ - return static_cast<QWebEngineViewAccessible *>(QAccessible::queryAccessibleInterface(m_view)); -} -#endif // QT_CONFIG(accessibility) - -} // namespace QtWebEngineCore - -#include "moc_render_widget_host_view_qt_delegate_widget.cpp" diff --git a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h deleted file mode 100644 index 1adebd3b5..000000000 --- a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h +++ /dev/null @@ -1,138 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtWebEngine module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef RENDER_WIDGET_HOST_VIEW_QT_DELEGATE_WIDGET_H -#define RENDER_WIDGET_HOST_VIEW_QT_DELEGATE_WIDGET_H - -#include "render_widget_host_view_qt_delegate.h" -#include "web_contents_adapter_client.h" - -#include <QAccessibleWidget> -#include <QQuickItem> -#include <QQuickWidget> - -QT_BEGIN_NAMESPACE -class QWebEnginePage; -class QWebEngineView; -class QWebEngineViewAccessible; -class QWebEngineViewPrivate; -QT_END_NAMESPACE - -namespace QtWebEngineCore { - -// Useful information keyboard and mouse QEvent propagation. -// A RenderWidgetHostViewQtDelegateWidget instance initialized as a popup will receive -// no keyboard focus (so all keyboard QEvents will be sent to the parent RWHVQD instance), -// but will still receive mouse input (all mouse QEvent moves and clicks will be given to the popup -// RWHVQD instance, and the mouse interaction area covers the surface of the whole parent -// QWebEngineView, and not only the smaller surface that an HTML select popup would occupy). -class RenderWidgetHostViewQtDelegateWidget : public QQuickWidget, public RenderWidgetHostViewQtDelegate { - Q_OBJECT -public: - RenderWidgetHostViewQtDelegateWidget(RenderWidgetHostViewQtDelegateClient *client, QWidget *parent = nullptr); - ~RenderWidgetHostViewQtDelegateWidget(); - - void initAsPopup(const QRect&) override; - QRectF viewGeometry() const override; - QRect windowGeometry() const override; - void setKeyboardFocus() override; - bool hasKeyboardFocus() override; - void lockMouse() override; - void unlockMouse() override; - void show() override; - void hide() override; - bool isVisible() const override; - QWindow* window() const override; - void updateCursor(const QCursor &) override; - void resize(int width, int height) override; - void move(const QPoint &screenPos) override; - void inputMethodStateChanged(bool editorVisible, bool passwordInput) override; - void setInputMethodHints(Qt::InputMethodHints) override; - void setClearColor(const QColor &color) override; - void unhandledWheelEvent(QWheelEvent *ev) override; - -protected: - bool event(QEvent *event) override; - void resizeEvent(QResizeEvent *resizeEvent) override; - void showEvent(QShowEvent *) override; - void hideEvent(QHideEvent *) override; - void closeEvent(QCloseEvent *event) override; - - QVariant inputMethodQuery(Qt::InputMethodQuery query) const override; - void adapterClientChanged(WebContentsAdapterClient *client) override; - -private Q_SLOTS: - void onWindowPosChanged(); - void connectRemoveParentBeforeParentDelete(); - void removeParentBeforeParentDelete(); - -private: - friend QWebEngineViewPrivate; - - RenderWidgetHostViewQtDelegateClient *m_client; - QScopedPointer<QQuickItem> m_rootItem; - bool m_isPopup; - QColor m_clearColor; - QList<QMetaObject::Connection> m_windowConnections; - QWebEnginePage *m_page = nullptr; - QMetaObject::Connection m_parentDestroyedConnection; - QMetaObject::Connection m_pageDestroyedConnection; -}; - -#if QT_CONFIG(accessibility) -class RenderWidgetHostViewQtDelegateWidgetAccessible : public QAccessibleWidget -{ -public: - RenderWidgetHostViewQtDelegateWidgetAccessible(RenderWidgetHostViewQtDelegateWidget *o, QWebEngineView *view); - - bool isValid() const override; - QAccessibleInterface *focusChild() const override; - int childCount() const override; - QAccessibleInterface *child(int index) const override; - int indexOfChild(const QAccessibleInterface *child) const override; - -private: - QWebEngineViewAccessible *viewAccessible() const; - QWebEngineView *m_view; -}; -#endif // QT_CONFIG(accessibility) - -} // namespace QtWebEngineCore - -#endif diff --git a/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp b/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp index 10aeede25..c747e6b8f 100644 --- a/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp +++ b/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp @@ -463,7 +463,6 @@ void tst_QQuickWebEngineView::transparentWebEngineViews() void tst_QQuickWebEngineView::inputMethod() { m_window->show(); - QTRY_VERIFY(qApp->focusObject()); QQuickItem *input; QQuickWebEngineView *view = webEngineView(); @@ -471,18 +470,21 @@ void tst_QQuickWebEngineView::inputMethod() view->setUrl(urlFromTestPath("html/inputmethod.html")); QVERIFY(waitForLoadSucceeded(view)); + QTRY_VERIFY(qobject_cast<QQuickItem *>(qApp->focusObject())); input = qobject_cast<QQuickItem *>(qApp->focusObject()); QVERIFY(!input->flags().testFlag(QQuickItem::ItemAcceptsInputMethod)); QVERIFY(!view->flags().testFlag(QQuickItem::ItemAcceptsInputMethod)); runJavaScript("document.getElementById('inputField').focus();"); QTRY_COMPARE(activeElementId(view), QStringLiteral("inputField")); + QTRY_VERIFY(qobject_cast<QQuickItem *>(qApp->focusObject())); input = qobject_cast<QQuickItem *>(qApp->focusObject()); QTRY_VERIFY(input->flags().testFlag(QQuickItem::ItemAcceptsInputMethod)); QVERIFY(view->flags().testFlag(QQuickItem::ItemAcceptsInputMethod)); runJavaScript("document.getElementById('inputField').blur();"); QTRY_VERIFY(activeElementId(view).isEmpty()); + QTRY_VERIFY(qobject_cast<QQuickItem *>(qApp->focusObject())); input = qobject_cast<QQuickItem *>(qApp->focusObject()); QTRY_VERIFY(!input->flags().testFlag(QQuickItem::ItemAcceptsInputMethod)); QVERIFY(!view->flags().testFlag(QQuickItem::ItemAcceptsInputMethod)); diff --git a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp index 57f6b24a8..63d39dd59 100644 --- a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp +++ b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp @@ -1441,15 +1441,18 @@ void tst_QWebEnginePage::comboBoxPopupPositionAfterChildMove() return viewWidth; }; + QCOMPARE(jsViewWidth(), originalViewWidth); + // Resize the "spacer" widget, and implicitly change the global position of the QWebEngineView. const int offset = 50; spacer.setMinimumWidth(spacer.size().width() + offset); + QTRY_COMPARE(jsViewWidth(), originalViewWidth - offset); makeClick(window, withTouch, view.mapTo(view.window(), elementCenter(view.page(), "foo"))); QTRY_VERIFY(popup = findNewTopLevelWindow(oldTlws)); QTRY_VERIFY(!popup->position().isNull()); - QCOMPARE(popupPos + QPoint(50, 0), popup->position()); + QCOMPARE(popupPos + QPoint(offset, 0), popup->position()); } #ifdef Q_OS_MAC diff --git a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp index 921b0c52f..883720490 100644 --- a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp +++ b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp @@ -106,6 +106,7 @@ private Q_SLOTS: void changePage(); void reusePage_data(); void reusePage(); + void setLoadedPage(); void microFocusCoordinates(); void focusInputTypes(); void unhandledKeyEventPropagation(); @@ -399,7 +400,7 @@ void tst_QWebEngineView::reusePage() view1->show(); QVERIFY(QTest::qWaitForWindowExposed(view1)); delete view1; - QVERIFY(page != 0); // deleting view must not have deleted the page, since it's not a child of view + QVERIFY(page != nullptr); // deleting view must not have deleted the page, since it's not a child of view QWebEngineView *view2 = new QWebEngineView; view2->setPage(page.data()); @@ -412,6 +413,23 @@ void tst_QWebEngineView::reusePage() QDir::setCurrent(QApplication::applicationDirPath()); } +void tst_QWebEngineView::setLoadedPage() +{ + // MEMO load page first to make sure that just simple attach to view would draw its content + QWebEnginePage page; + QSignalSpy loadSpy(&page, &QWebEnginePage::loadFinished); + page.setHtml(QString("<html><body bgcolor=\"%1\"></body></html>").arg(QColor(Qt::yellow).name())); + QTRY_VERIFY(loadSpy.count() == 1 && loadSpy.first().first().toBool()); + + QWebEngineView view; + view.resize(480, 320); + view.show(); + QVERIFY(QTest::qWaitForWindowExposed(&view)); + + view.setPage(&page); + QTRY_COMPARE(view.grab().toImage().pixelColor(QPoint(view.width() / 2, view.height() / 2)), Qt::yellow); +} + // Class used in crashTests class WebViewCrashTest : public QObject { Q_OBJECT diff --git a/tests/auto/widgets/spellchecking/tst_spellchecking.cpp b/tests/auto/widgets/spellchecking/tst_spellchecking.cpp index 7263904ce..738010ac8 100644 --- a/tests/auto/widgets/spellchecking/tst_spellchecking.cpp +++ b/tests/auto/widgets/spellchecking/tst_spellchecking.cpp @@ -170,6 +170,7 @@ void tst_Spellchecking::spellcheck() QVariantList list = evaluateJavaScriptSync(m_view->page(), "findWordPosition('I lowe Qt ....','lowe');").toList(); QRect rect(list[0].value<int>(),list[1].value<int>(),list[2].value<int>(),list[3].value<int>()); + QTRY_VERIFY(m_view->focusWidget()); //type text, spellchecker needs time QTest::mouseMove(m_view->focusWidget(), QPoint(20,20)); QTest::mousePress(m_view->focusWidget(), Qt::LeftButton, {}, QPoint(20,20)); @@ -182,7 +183,7 @@ void tst_Spellchecking::spellcheck() // make sure text is there QString result = evaluateJavaScriptSync(m_view->page(), "text();").toString(); - QVERIFY(result == text); + QCOMPARE(result, text); bool gotMisspelledWord = false; // clumsy QTRY_VERIFY still execs expr after first success QString detail; |