summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorVolker Hilsheimer <volker.hilsheimer@qt.io>2021-10-23 20:21:50 +0200
committerVolker Hilsheimer <volker.hilsheimer@qt.io>2021-11-15 18:25:50 +0100
commit22634e00794e72d68e7578e1962f9f2023870749 (patch)
treef5af2820b6f2b29e5aba30e74ffaaa3e6b05268b /src
parent9879d41d05b681bc41bbc97a66b03a04363fd44c (diff)
Make sure we paint overlapped children and siblings when moving far
In paintAndFlush, QWidgetRepaintManager subtracts opaque children if the target isn't overlapped and isMoved is set to true. So in moveRect, set isMoved to true after the blitting of movable areas, and reset it to false if we have overlapped sibling or child regions. Otherwise, moving so far that sourceRect is invalid (none of the original pixels are visible after the move) we end up in a code path that sets isMoved to true even with overlapping children or siblings, which then breaks paintAndFlush's assumptions. Reuse the test case written by Sergiy Korobov <tiamatenko@gmail.com> in earlier attempts to fix this bug. Fixes: QTBUG-26269 Pick-to: 6.2 Change-Id: If7443863f5eee79a80220cd587522122f42a21e4 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/widgets/kernel/qwidgetrepaintmanager.cpp24
1 files changed, 13 insertions, 11 deletions
diff --git a/src/widgets/kernel/qwidgetrepaintmanager.cpp b/src/widgets/kernel/qwidgetrepaintmanager.cpp
index 977a746c5a..d9375c7281 100644
--- a/src/widgets/kernel/qwidgetrepaintmanager.cpp
+++ b/src/widgets/kernel/qwidgetrepaintmanager.cpp
@@ -449,12 +449,8 @@ void QWidgetPrivate::moveRect(const QRect &rect, int dx, int dy)
QWidget *pw = q->parentWidget();
QPoint toplevelOffset = pw->mapTo(tlw, QPoint());
QWidgetPrivate *pd = pw->d_func();
- QRect clipR(pd->clipRect());
+ const QRect clipR(pd->clipRect());
const QRect newRect(rect.translated(dx, dy));
- QRect destRect = rect.intersected(clipR);
- if (destRect.isValid())
- destRect = destRect.translated(dx, dy).intersected(clipR);
- const QRect sourceRect(destRect.translated(-dx, -dy));
const QRect parentRect(rect & clipR);
const bool nativeWithTextureChild = textureChildSeen && hasPlatformWindow(q);
@@ -476,9 +472,13 @@ void QWidgetPrivate::moveRect(const QRect &rect, int dx, int dy)
pd->invalidateBackingStore(parentR);
invalidateBackingStore((newRect & clipR).translated(-data.crect.topLeft()));
} else {
+ QRect destRect = rect.intersected(clipR);
+ if (destRect.isValid())
+ destRect = destRect.translated(dx, dy).intersected(clipR);
+ const QRect sourceRect(destRect.translated(-dx, -dy));
QWidgetRepaintManager *repaintManager = x->repaintManager.get();
- QRegion childExpose(newRect & clipR);
+ QRegion childExpose = QRegion(newRect) & clipR;
QRegion overlappedExpose;
if (sourceRect.isValid()) {
@@ -493,6 +493,7 @@ void QWidgetPrivate::moveRect(const QRect &rect, int dx, int dy)
childExpose -= r.translated(dx, dy);
}
}
+ isMoved = true;
}
childExpose -= overlappedExpose;
@@ -503,14 +504,17 @@ void QWidgetPrivate::moveRect(const QRect &rect, int dx, int dy)
const bool childUpdatesEnabled = q->updatesEnabled();
if (childUpdatesEnabled) {
+ // As per paintAndFlush, reset isMoved if we have overlapping
+ // or child regions that need to be painted.
if (!overlappedExpose.isEmpty()) {
overlappedExpose.translate(-data.crect.topLeft());
invalidateBackingStore(overlappedExpose);
+ isMoved = false;
}
if (!childExpose.isEmpty()) {
childExpose.translate(-data.crect.topLeft());
repaintManager->markDirty(childExpose, q);
- isMoved = true;
+ isMoved = false;
}
}
@@ -519,12 +523,10 @@ void QWidgetPrivate::moveRect(const QRect &rect, int dx, int dy)
if (extra && extra->hasMask)
parentExpose += QRegion(newRect) - extra->mask.translated(data.crect.topLeft());
- if (!parentExpose.isEmpty()) {
+ if (!parentExpose.isEmpty())
repaintManager->markDirty(parentExpose, pw);
- pd->isMoved = true;
- }
- if (childUpdatesEnabled) {
+ if (childUpdatesEnabled && sourceRect.isValid()) {
QRegion needsFlush(sourceRect);
needsFlush += destRect;
repaintManager->markNeedsFlush(pw, needsFlush, toplevelOffset);