diff options
| author | Michal Klocek <michal.klocek@qt.io> | 2025-10-20 10:10:56 +0200 |
|---|---|---|
| committer | Michal Klocek <michal.klocek@qt.io> | 2025-12-01 17:11:29 +0100 |
| commit | 452e0aaed82ee01833455ef4616fb59a9fc7fc2b (patch) | |
| tree | 413bb8733db0815aea4839e6f22b983beb080c2a | |
| parent | 68322bd57bd790d609e85599d3c524c9650e31c2 (diff) | |
Make html comoboxes great again (2/2)
This patch is band-aid patch to handle QQuickWebEngineView
transformations like scaling and rotation.
Before this patch we used mapToGlobal to get viewGeometry
however if the item is transformed by rotation and
scaling the mapToGlobal will return something not expected by
Chromium. Imagine:
--------- -------
| aaaaa | | aaaa|
| bbbbb | => rotates 90 => | bbbb|
| ccccc | | cccc|
--------- | |
-------
So Chromium still 'thinks' that content is displayed
horizontally and just window geometry changed.
Moreover, mapToGlobal for rect QRectF(tl,rb) when this is
rotated by 90 degree will return QRectF(tr,bl).nomralized()
in global coordinates. This is not correct geometry.
As band-aid solution for transform case, go with
fixed view geometry of QRect(0,0,widith(),hight())
This will allow to Chromium get untransformed popup position,
which we later transform in delegate. Fix and simplify
transformation calculations in QQuickWindow delegate
using just global screen coordinates.
Note having fixed view geometry will have side effect
like accessibility mappings broken or screen edge detection
not working (if dropdown comobox can not be displayed due to
screen border it is simply moved over the combobox filed)
Therefore, this is just band-aid solution, which covers anyway
rare use case of doing the QQuickWebview transformation
within the scene.
Tested with openbox, weston, mutter-wayland, mutter-xwayland.
Pick-to: 6.10
Change-Id: I3c2d662ccd093793da6b5e192d79c9e22e451789
Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
4 files changed, 28 insertions, 38 deletions
diff --git a/src/core/render_widget_host_view_qt_delegate_item.cpp b/src/core/render_widget_host_view_qt_delegate_item.cpp index 4886351ba..aaf8bb263 100644 --- a/src/core/render_widget_host_view_qt_delegate_item.cpp +++ b/src/core/render_widget_host_view_qt_delegate_item.cpp @@ -55,19 +55,30 @@ void RenderWidgetHostViewQtDelegateItem::initAsPopup(const QRect &screenRect) { Q_ASSERT(m_isPopup); setSize(screenRect.size()); + m_popupRect = screenRect; if (m_widgetDelegate) m_widgetDelegate->InitAsPopup(screenRect); } QRectF RenderWidgetHostViewQtDelegateItem::viewGeometry() const { - // Transform the entire rect to find the correct top left corner. - const QPointF p1 = mapToGlobal(QPointF(0, 0)); - const QPointF p2 = mapToGlobal(QPointF(width(), height())); - QRectF geometry = QRectF(p1, p2).normalized(); - // But keep the size untransformed to behave like other QQuickItems. - geometry.setSize(size()); - return geometry; + const QTransform transform = itemTransform(nullptr, nullptr); + + const bool isTransformed = transform.type() > QTransform::TxTranslate; + + if (!isTransformed) { + // find the correct top left corner + const QPointF tl = mapToGlobal(QPointF(0, 0)); + return QRectF(tl, size()); + } else if (!m_isPopup) { + // keep it simply untransformed, as we transform only delegate as there no way + // to return screen rect which would makes sense in that case + // this is just band-aid workaround to support rotation and scaling + return QRectF(QPointF(0, 0), size()); + } else { + // this is transformed and popup, keep chromium unaware of transformations + return m_popupRect; + } } QRect RenderWidgetHostViewQtDelegateItem::windowGeometry() const diff --git a/src/core/render_widget_host_view_qt_delegate_item.h b/src/core/render_widget_host_view_qt_delegate_item.h index a4246b8ff..6775e4063 100644 --- a/src/core/render_widget_host_view_qt_delegate_item.h +++ b/src/core/render_widget_host_view_qt_delegate_item.h @@ -115,6 +115,7 @@ private: RenderWidgetHostViewQtDelegateClient *m_client; bool m_isPopup; + QRectF m_popupRect; QColor m_clearColor; Qt::InputMethodHints m_inputMethodHints = {}; QList<QMetaObject::Connection> m_windowConnections; 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 9e546089b..3ad88ca39 100644 --- a/src/webenginequick/render_widget_host_view_qt_delegate_quickwindow.cpp +++ b/src/webenginequick/render_widget_host_view_qt_delegate_quickwindow.cpp @@ -27,19 +27,6 @@ static inline struct ItemTransform getTransformValuesFromItemTree(QQuickItem *it return returnValue; } -static inline QPointF transformPoint(const QPointF &point, const QTransform &transform, - const QPointF &offset, const QQuickItem *parent) -{ - // make scene vector - QPointF a = point - offset; - // apply local transformation - a = transform.map(a); - // make screen coordinates - a = parent->mapFromScene(a); - a = parent->mapToGlobal(a); - return a; -} - RenderWidgetHostViewQtDelegateQuickWindow::RenderWidgetHostViewQtDelegateQuickWindow( RenderWidgetHostViewQtDelegateItem *realDelegate, QWindow *parent) : QQuickWindow(), m_realDelegate(realDelegate), m_virtualParent(nullptr), m_transformed(false) @@ -64,37 +51,29 @@ void RenderWidgetHostViewQtDelegateQuickWindow::setVirtualParent(QQuickItem *vir } // rect is visual geometry in form of global screen coordinates -// chromium knows nothing about local transformation +// if menu is transformed screen rect is simply given in screen +// coordinates where parent geometry is simply QRect(0,0,size()) void RenderWidgetHostViewQtDelegateQuickWindow::InitAsPopup(const QRect &rect) { // To decide if there is a scale or rotation, we check it from the transfrom // to also cover the case where the scale is higher up in the item tree. QTransform transform = m_virtualParent->itemTransform(nullptr, nullptr); - m_transformed = transform.isRotating() || transform.isScaling(); + m_transformed = transform.type() > QTransform::TxTranslate; if (m_transformed) { // code below tries to cover the case where webengine view is rotated or scaled, // the code assumes the rotation is in the form of 90, 180, 270 degrees // to archive that we keep chromium unaware of transformation and we transform // just the window content. - m_rect = rect; - // get parent window (scene) offset - QPointF offset = m_virtualParent->mapFromScene(QPoint(0, 0)); - offset = m_virtualParent->mapToGlobal(offset); - // get local transform - QPointF tl = transformPoint(rect.topLeft(), transform, offset, m_virtualParent); - QPointF br = transformPoint(rect.bottomRight(), transform, offset, m_virtualParent); - QRectF popupRect(tl, br); - popupRect = popupRect.normalized(); - // include offset from parent window - popupRect.moveTo(popupRect.topLeft() - offset); - setGeometry(popupRect.adjusted(0, 0, 1, 1).toRect()); - // add offset since screenRect and transformed popupRect one are different and - // we want to rotate in center. + QRectF popupRect = transform.mapRect(rect); + // adjust for scene offset + const QPointF offset = + m_virtualParent->mapToGlobal(m_virtualParent->mapFromScene(QPoint(0, 0))); + popupRect.translate(offset); + setGeometry(popupRect.normalized().toRect()); m_realDelegate->setX(-rect.width() / 2.0 + geometry().width() / 2.0); m_realDelegate->setY(-rect.height() / 2.0 + geometry().height() / 2.0); m_realDelegate->setTransformOrigin(QQuickItem::Center); - // We need to read the values for scale and rotation from the item tree as it is not // sufficient to only use the virtual parent item and its parent for the case that the // scale or rotation is applied higher up the item tree. diff --git a/src/webenginequick/render_widget_host_view_qt_delegate_quickwindow_p.h b/src/webenginequick/render_widget_host_view_qt_delegate_quickwindow_p.h index c39d2f24a..dff1b81a0 100644 --- a/src/webenginequick/render_widget_host_view_qt_delegate_quickwindow_p.h +++ b/src/webenginequick/render_widget_host_view_qt_delegate_quickwindow_p.h @@ -49,7 +49,6 @@ public: private: QPointer<RenderWidgetHostViewQtDelegateItem> m_realDelegate; QQuickItem *m_virtualParent; - QRect m_rect; bool m_transformed; }; |
