summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjørn Erik Nilsen <bjorn.nilsen@nokia.com>2009-10-28 11:39:33 (GMT)
committerBjørn Erik Nilsen <bjorn.nilsen@nokia.com>2009-10-28 12:56:27 (GMT)
commit992f5cef19ce9e313dd06279c47d7535c6dbc857 (patch)
tree103307bcde9d893ce7d5cefb866c33dd5e1ec359
parentf62e0f8323304b2afbf2e3b918d611ea1d0f6856 (diff)
downloadQt-992f5cef19ce9e313dd06279c47d7535c6dbc857.zip
Qt-992f5cef19ce9e313dd06279c47d7535c6dbc857.tar.gz
Qt-992f5cef19ce9e313dd06279c47d7535c6dbc857.tar.bz2
Wrong caching of opaque children in QWidget.
The opaque children cache was clipped to all the ancestors up to the top-level, which means whenever a widget changes geometry all the children must be invalidated. However, the bug was that we didn't invalidate the children, and that is of course slow so we don't want to do it either. A better solution is to only clip the children cache to the widget itself (widget->rect() instead of widget->clipRect()), and we can perfectly do this because the region we subtract the opaque children from is already inside the clipRect(). Auto-test included. Task-number: QTBUG-4245 (related to)
-rw-r--r--src/gui/kernel/qwidget.cpp22
-rw-r--r--src/gui/kernel/qwidget_p.h1
-rw-r--r--tests/auto/qwidget/tst_qwidget.cpp42
3 files changed, 51 insertions, 14 deletions
diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp
index 5fa9a92..1951ab2 100644
--- a/src/gui/kernel/qwidget.cpp
+++ b/src/gui/kernel/qwidget.cpp
@@ -1825,18 +1825,6 @@ void QWidgetPrivate::setDirtyOpaqueRegion()
pd->setDirtyOpaqueRegion();
}
-QRegion QWidgetPrivate::getOpaqueRegion() const
-{
- Q_Q(const QWidget);
-
- QRegion r = isOpaque ? q->rect() : getOpaqueChildren();
- if (extra && extra->hasMask)
- r &= extra->mask;
- if (r.isEmpty())
- return r;
- return r & clipRect();
-}
-
const QRegion &QWidgetPrivate::getOpaqueChildren() const
{
if (!dirtyOpaqueChildren)
@@ -1851,9 +1839,17 @@ const QRegion &QWidgetPrivate::getOpaqueChildren() const
continue;
const QPoint offset = child->geometry().topLeft();
- that->opaqueChildren += child->d_func()->getOpaqueRegion().translated(offset);
+ QWidgetPrivate *childd = child->d_func();
+ QRegion r = childd->isOpaque ? child->rect() : childd->getOpaqueChildren();
+ if (childd->extra && childd->extra->hasMask)
+ r &= childd->extra->mask;
+ if (r.isEmpty())
+ continue;
+ r.translate(offset);
+ that->opaqueChildren += r;
}
+ that->opaqueChildren &= q_func()->rect();
that->dirtyOpaqueChildren = false;
return that->opaqueChildren;
diff --git a/src/gui/kernel/qwidget_p.h b/src/gui/kernel/qwidget_p.h
index 159a3f2..5cea641 100644
--- a/src/gui/kernel/qwidget_p.h
+++ b/src/gui/kernel/qwidget_p.h
@@ -386,7 +386,6 @@ public:
bool paintOnScreen() const;
void invalidateGraphicsEffectsRecursively();
- QRegion getOpaqueRegion() const;
const QRegion &getOpaqueChildren() const;
void setDirtyOpaqueRegion();
diff --git a/tests/auto/qwidget/tst_qwidget.cpp b/tests/auto/qwidget/tst_qwidget.cpp
index 050d1c5..9c421d1 100644
--- a/tests/auto/qwidget/tst_qwidget.cpp
+++ b/tests/auto/qwidget/tst_qwidget.cpp
@@ -332,6 +332,7 @@ private slots:
void doubleRepaint();
#ifndef Q_WS_MAC
void resizeInPaintEvent();
+ void opaqueChildren();
#endif
void setMaskInResizeEvent();
@@ -8272,6 +8273,47 @@ void tst_QWidget::resizeInPaintEvent()
// Make sure the resize triggers another update.
QTRY_COMPARE(widget.numPaintEvents, 1);
}
+
+void tst_QWidget::opaqueChildren()
+{
+ QWidget widget;
+ widget.resize(200, 200);
+
+ QWidget child(&widget);
+ child.setGeometry(-700, -700, 200, 200);
+
+ QWidget grandChild(&child);
+ grandChild.resize(200, 200);
+
+ QWidget greatGrandChild(&grandChild);
+ greatGrandChild.setGeometry(50, 50, 200, 200);
+ greatGrandChild.setPalette(Qt::red);
+ greatGrandChild.setAutoFillBackground(true); // Opaque child widget.
+
+ widget.show();
+#ifdef Q_WS_X11
+ qt_x11_wait_for_window_manager(&widget);
+#endif
+ QTest::qWait(100);
+
+ // Child, grandChild and greatGrandChild are outside the ancestor clip.
+ QRegion expectedOpaqueRegion(50, 50, 150, 150);
+ QCOMPARE(qt_widget_private(&grandChild)->getOpaqueChildren(), expectedOpaqueRegion);
+
+ // Now they are all inside the ancestor clip.
+ child.setGeometry(50, 50, 150, 150);
+ QCOMPARE(qt_widget_private(&grandChild)->getOpaqueChildren(), expectedOpaqueRegion);
+
+ // Set mask on greatGrandChild.
+ const QRegion mask(10, 10, 50, 50);
+ greatGrandChild.setMask(mask);
+ expectedOpaqueRegion &= mask.translated(50, 50);
+ QCOMPARE(qt_widget_private(&grandChild)->getOpaqueChildren(), expectedOpaqueRegion);
+
+ // Make greatGrandChild "transparent".
+ greatGrandChild.setAutoFillBackground(false);
+ QCOMPARE(qt_widget_private(&grandChild)->getOpaqueChildren(), QRegion());
+}
#endif