summaryrefslogtreecommitdiffstats
path: root/src/xmlpatterns/common.pri
diff options
context:
space:
mode:
Diffstat (limited to 'src/xmlpatterns/common.pri')
-rw-r--r--src/xmlpatterns/common.pri1
1 files changed, 1 insertions, 0 deletions
diff --git a/src/xmlpatterns/common.pri b/src/xmlpatterns/common.pri
index 2573a26..27253d8 100644
--- a/src/xmlpatterns/common.pri
+++ b/src/xmlpatterns/common.pri
@@ -10,6 +10,7 @@ INCLUDEPATH += $$PWD/acceltree \
$$PWD/iterators \
$$PWD/janitors \
$$PWD/parser \
+ $$PWD/schema \
$$PWD/type \
$$PWD/utils
verting files from Windows style line endings (CRLF) +to Unix style line endings (LF). To avoid this problem, uncompress the file +again and give the option "-a" to unzip, which will then add the correct line +endings. + +Q: I'm running Windows XP and I downloaded the qt-win-eval-4.5.0-vs2008.exe +version of Qt. However, when I try to run the examples I get an error saying: +"The application failed to start because the application configuration is +incorrect. Reinstalling the application may fix this problem.". I reinstalled +the package but the error persists. What am I doing wrong? +A: The problem is an incorrect version of the CRT. Visual studio requires CRT90 +while Windows XP comes with CRT80. To solve this problem, please install the +2008 CRT redistributable package from Microsoft. diff --git a/LGPL_EXCEPTION.TXT b/LGPL_EXCEPTION.TXT deleted file mode 100644 index 8d0f85e..0000000 --- a/LGPL_EXCEPTION.TXT +++ /dev/null @@ -1,3 +0,0 @@ -Nokia Qt LGPL Exception version 1.0 - -As a special exception to the GNU Lesser General Public License version 2.1, the object code form of a "work that uses the Library" may incorporate material from a header file that is part of the Library. You may distribute such object code under terms of your choice, provided that the incorporated material (i) does not exceed more than 5% of the total size of the Library; and (ii) is limited to numerical parameters, data structure layouts, accessors, macros, inline functions and templates. \ No newline at end of file diff --git a/LGPL_EXCEPTION.txt b/LGPL_EXCEPTION.txt new file mode 100644 index 0000000..8d0f85e --- /dev/null +++ b/LGPL_EXCEPTION.txt @@ -0,0 +1,3 @@ +Nokia Qt LGPL Exception version 1.0 + +As a special exception to the GNU Lesser General Public License version 2.1, the object code form of a "work that uses the Library" may incorporate material from a header file that is part of the Library. You may distribute such object code under terms of your choice, provided that the incorporated material (i) does not exceed more than 5% of the total size of the Library; and (ii) is limited to numerical parameters, data structure layouts, accessors, macros, inline functions and templates. \ No newline at end of file -- cgit v0.12 From cf65dea821a2ba796bb1f32c80de6b9db224dff5 Mon Sep 17 00:00:00 2001 From: Kavindra Devi Palaraja Date: Mon, 6 Apr 2009 13:15:00 +0200 Subject: Doc - Mentioned what the default filters are for QFileSystemModel::filter(). Task-number: 250285 Reviewed-by: Benjamin Poulain --- src/gui/dialogs/qfilesystemmodel.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/gui/dialogs/qfilesystemmodel.cpp b/src/gui/dialogs/qfilesystemmodel.cpp index c7b3137..012d3a1 100644 --- a/src/gui/dialogs/qfilesystemmodel.cpp +++ b/src/gui/dialogs/qfilesystemmodel.cpp @@ -1430,7 +1430,10 @@ void QFileSystemModel::setFilter(QDir::Filters filters) } /*! - Returns the filter specification for the directory model. + Returns the filter specified for the directory model. + + If a filter has not been set, the default filter is QDir::AllEntries | + QDir::NoDotAndDotDot | QDir::AllDirs. \sa QDir::Filters */ -- cgit v0.12 From e27743bdeda7aa3cb42f2d81a521121f8ee04eae Mon Sep 17 00:00:00 2001 From: Bjoern Erik Nilsen Date: Wed, 25 Feb 2009 12:18:28 +0100 Subject: Fixes: Optimize QGraphicsView::itemUpdated. Task: - RevBy: Andreas AutoTest: - Details: Accumulate the parentToItem transform as we iterate instead of creating it from bottom-up each time. --- src/gui/graphicsview/qgraphicsview.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp index 2f7f57a..9b0e12d 100644 --- a/src/gui/graphicsview/qgraphicsview.cpp +++ b/src/gui/graphicsview/qgraphicsview.cpp @@ -804,10 +804,17 @@ void QGraphicsViewPrivate::itemUpdated(QGraphicsItem *item, const QRectF &rect) if (item->isClipped()) { // Minimize unnecessary redraw. QGraphicsItem *p = item; + QTransform xform; + QGraphicsItem *lastTransformItem = 0; while ((p = p->d_ptr->parent)) { if (p->flags() & QGraphicsItem::ItemClipsChildrenToShape) { - updateRect &= p->itemTransform(item).mapRect(p->boundingRect()); - if (updateRect.isNull()) + if (!lastTransformItem) + xform = item->itemTransform(p); + else + xform *= lastTransformItem->itemTransform(p); + lastTransformItem = p; + updateRect &= xform.inverted().mapRect(p->boundingRect()); + if (updateRect.isEmpty()) return; } @@ -815,7 +822,7 @@ void QGraphicsViewPrivate::itemUpdated(QGraphicsItem *item, const QRectF &rect) break; } - if (updateRect.isNull()) + if (updateRect.isEmpty()) return; } -- cgit v0.12 From be6be8c73929f2ddee9a02f59db05c3ba453a63e Mon Sep 17 00:00:00 2001 From: Bjoern Erik Nilsen Date: Thu, 26 Feb 2009 14:49:47 +0100 Subject: Fixes: Optimize QGraphicsViewPrivate::updateRect()/updateRegion(). Details: Those cut-offs are extremely important. After few seconds interaction with the iphone demo, updateRect() was called approx. 3000 times with an empty rect. Then imagine what happens when having e.g. FullViewportUpdate. We do q->viewport()->update() JUST FOR FUN! --- src/gui/graphicsview/qgraphicsview.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp index 9b0e12d..aa5f069 100644 --- a/src/gui/graphicsview/qgraphicsview.cpp +++ b/src/gui/graphicsview/qgraphicsview.cpp @@ -928,6 +928,9 @@ void QGraphicsViewPrivate::updateAll() void QGraphicsViewPrivate::updateRegion(const QRegion &r) { + if (r.isEmpty()) + return; + Q_Q(QGraphicsView); // Rect intersects viewport - update everything? @@ -976,6 +979,9 @@ void QGraphicsViewPrivate::updateRegion(const QRegion &r) void QGraphicsViewPrivate::updateRect(const QRect &r) { + if (r.isEmpty()) + return; + Q_Q(QGraphicsView); // Rect intersects viewport - update everything? -- cgit v0.12 From e9fa8ba1ad0b0b2d3363fb33635071677f42b983 Mon Sep 17 00:00:00 2001 From: Bjoern Erik Nilsen Date: Thu, 26 Feb 2009 15:00:08 +0100 Subject: Fixes: Cleanup calls to QGraphicsViewPrivate::updateRect()/updateRegion() Details: Checking for QRect::isNull() was wrong in the first place, and checking for isEmpty()/isNull() is overhead after 4a491a84aeba68279927597a261522dcc23bb3ff. --- src/gui/graphicsview/qgraphicsview.cpp | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp index aa5f069..b92c886 100644 --- a/src/gui/graphicsview/qgraphicsview.cpp +++ b/src/gui/graphicsview/qgraphicsview.cpp @@ -829,17 +829,10 @@ void QGraphicsViewPrivate::itemUpdated(QGraphicsItem *item, const QRectF &rect) // Map the rect to view coordinates. QRect vr = viewport->rect(); - if (!item->d_ptr->hasBoundingRegionGranularity) { - QRect r = mapToViewRect(item, updateRect) & vr; - if (r.isNull()) - return; - this->updateRect(r); - } else { - QRegion r = mapToViewRegion(item, updateRect) & vr; - if (r.isEmpty()) - return; - updateRegion(r); - } + if (!item->d_ptr->hasBoundingRegionGranularity) + this->updateRect(mapToViewRect(item, updateRect) & vr); + else + updateRegion(mapToViewRegion(item, updateRect) & vr); } void QGraphicsViewPrivate::updateLater() @@ -863,9 +856,7 @@ void QGraphicsViewPrivate::_q_updateLaterSlot() for (int i = 0; i < dirtyItems.size(); ++i) { const QGraphicsItem *item = dirtyItems.at(i); QTransform x = item->sceneTransform() * viewTransform; - QRect viewRect = x.mapRect(item->boundingRect()).toAlignedRect() & vr; - if (!viewRect.isNull()) - updateRect(viewRect); + updateRect(x.mapRect(item->boundingRect()).toAlignedRect() & vr); } dirtyRectCount += dirtyRects.size(); -- cgit v0.12 From 8a2ebc96220f50be3a9c382c32d7eaab89921ff7 Mon Sep 17 00:00:00 2001 From: Bjoern Erik Nilsen Date: Thu, 26 Feb 2009 15:47:04 +0100 Subject: Fixes: Use QRect::isEmpty() rather than isNull() if possible. RevBy: Andreas Details: Note that isNull() implies isEmpty(), but it only catches the cases where width and height is 0. --- src/gui/graphicsview/qgraphicsitem.cpp | 2 +- src/gui/graphicsview/qgraphicsscene.cpp | 2 +- src/gui/graphicsview/qgraphicsview.cpp | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index 83a7e67..b982393 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -3757,7 +3757,7 @@ bool QGraphicsItemPrivate::isProxyWidget() const */ void QGraphicsItem::update(const QRectF &rect) { - if (d_ptr->dirty) + if (d_ptr->dirty || (rect.isEmpty() && !rect.isNull())) return; if (d_ptr->scene && isVisible()) { if (CacheMode(d_ptr->cacheMode) != NoCache) { diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index ff46e2e..9b06945 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -3455,7 +3455,7 @@ QVariant QGraphicsScene::inputMethodQuery(Qt::InputMethodQuery query) const void QGraphicsScene::update(const QRectF &rect) { Q_D(QGraphicsScene); - if (d->updateAll) + if (d->updateAll || (rect.isEmpty() && !rect.isNull())) return; // Check if anyone's connected; if not, we can send updates directly to diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp index b92c886..f88918f 100644 --- a/src/gui/graphicsview/qgraphicsview.cpp +++ b/src/gui/graphicsview/qgraphicsview.cpp @@ -862,7 +862,7 @@ void QGraphicsViewPrivate::_q_updateLaterSlot() dirtyRectCount += dirtyRects.size(); bool noUpdate = !fullUpdatePending && viewportUpdateMode == QGraphicsView::FullViewportUpdate; - if ((dirtyRectCount > 0 || !dirtyBoundingRect.isNull()) && !fullUpdatePending && !noUpdate) { + if ((dirtyRectCount > 0 || !dirtyBoundingRect.isEmpty()) && !fullUpdatePending && !noUpdate) { if (viewportUpdateMode == QGraphicsView::BoundingRectViewportUpdate || (viewportUpdateMode == QGraphicsView::SmartViewportUpdate && dirtyRectCount >= QGRAPHICSVIEW_REGION_RECT_THRESHOLD)) { @@ -3284,7 +3284,7 @@ void QGraphicsView::mouseMoveEvent(QMouseEvent *event) } // Update old rubberband - if (d->viewportUpdateMode != QGraphicsView::NoViewportUpdate && !d->rubberBandRect.isNull()) { + if (d->viewportUpdateMode != QGraphicsView::NoViewportUpdate && !d->rubberBandRect.isEmpty()) { if (d->viewportUpdateMode != FullViewportUpdate) viewport()->update(d->rubberBandRegion(viewport(), d->rubberBandRect)); else @@ -3466,7 +3466,7 @@ void QGraphicsView::paintEvent(QPaintEvent *event) QPainter painter(viewport()); QTransform original = painter.worldTransform(); #ifndef QT_NO_RUBBERBAND - if (d->rubberBanding && !d->rubberBandRect.isNull()) + if (d->rubberBanding && !d->rubberBandRect.isEmpty()) painter.save(); #endif // Set up render hints @@ -3561,7 +3561,7 @@ void QGraphicsView::paintEvent(QPaintEvent *event) #ifndef QT_NO_RUBBERBAND // Rubberband - if (d->rubberBanding && !d->rubberBandRect.isNull()) { + if (d->rubberBanding && !d->rubberBandRect.isEmpty()) { painter.restore(); QStyleOptionRubberBand option; option.initFrom(viewport()); @@ -3645,7 +3645,7 @@ void QGraphicsView::scrollContentsBy(int dx, int dy) #ifndef QT_NO_RUBBERBAND // Update old rubberband - if (d->viewportUpdateMode != QGraphicsView::NoViewportUpdate && !d->rubberBandRect.isNull()) { + if (d->viewportUpdateMode != QGraphicsView::NoViewportUpdate && !d->rubberBandRect.isEmpty()) { if (d->viewportUpdateMode != FullViewportUpdate) viewport()->update(d->rubberBandRegion(viewport(), d->rubberBandRect)); else -- cgit v0.12 From eda77b7c410a59d1b77c263994679452613d9d0b Mon Sep 17 00:00:00 2001 From: Bjoern Erik Nilsen Date: Fri, 27 Feb 2009 16:00:55 +0100 Subject: Fixes: Small optimization: reduce calls to QTransform::type(). Task: none RevBy: Ariya Hidayat AutoTest: Still pass. Details: QTransform::type() is cached, so only the first call to it should be expensive. However, it is not inlined so there's an overhead involved (especially when these functions are called a gazillion times). --- src/gui/painting/qtransform.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/gui/painting/qtransform.cpp b/src/gui/painting/qtransform.cpp index c70208c..c120143 100644 --- a/src/gui/painting/qtransform.cpp +++ b/src/gui/painting/qtransform.cpp @@ -1222,7 +1222,8 @@ static QPolygonF mapProjective(const QTransform &transform, const QPolygonF &pol */ QPolygonF QTransform::map(const QPolygonF &a) const { - if (type() >= QTransform::TxProject) + TransformationType t = type(); + if (t >= QTransform::TxProject) return mapProjective(*this, a); int size = a.size(); @@ -1231,7 +1232,6 @@ QPolygonF QTransform::map(const QPolygonF &a) const const QPointF *da = a.constData(); QPointF *dp = p.data(); - TransformationType t = type(); for(i = 0; i < size; ++i) { MAP(da[i].xp, da[i].yp, dp[i].xp, dp[i].yp); } @@ -1249,7 +1249,8 @@ QPolygonF QTransform::map(const QPolygonF &a) const */ QPolygon QTransform::map(const QPolygon &a) const { - if (type() >= QTransform::TxProject) + TransformationType t = type(); + if (t >= QTransform::TxProject) return mapProjective(*this, QPolygonF(a)).toPolygon(); int size = a.size(); @@ -1258,7 +1259,6 @@ QPolygon QTransform::map(const QPolygon &a) const const QPoint *da = a.constData(); QPoint *dp = p.data(); - TransformationType t = type(); for(i = 0; i < size; ++i) { qreal nx = 0, ny = 0; MAP(da[i].xp, da[i].yp, nx, ny); @@ -2061,10 +2061,11 @@ QTransform::operator QVariant() const Q_GUI_EXPORT bool qt_scaleForTransform(const QTransform &transform, qreal *scale) { - if (transform.type() <= QTransform::TxTranslate) { + const QTransform::TransformationType type = transform.type(); + if (type <= QTransform::TxTranslate) { *scale = 1; return true; - } else if (transform.type() == QTransform::TxScale) { + } else if (type == QTransform::TxScale) { const qreal xScale = qAbs(transform.m11()); const qreal yScale = qAbs(transform.m22()); *scale = qMax(xScale, yScale); @@ -2076,7 +2077,7 @@ bool qt_scaleForTransform(const QTransform &transform, qreal *scale) const qreal yScale = transform.m12() * transform.m12() + transform.m22() * transform.m22(); *scale = qSqrt(qMax(xScale, yScale)); - return transform.type() == QTransform::TxRotate && qFuzzyCompare(xScale, yScale); + return type == QTransform::TxRotate && qFuzzyCompare(xScale, yScale); } QT_END_NAMESPACE -- cgit v0.12 From b4456f8775c36bcb2ceef9ca1a00c7765f1d2735 Mon Sep 17 00:00:00 2001 From: Bjoern Erik Nilsen Date: Fri, 27 Feb 2009 18:10:08 +0100 Subject: Fixes: Get rid of a gazillion calls to QTransform::operator*=. Details: Be a little bit smarter before doing *= :) --- src/gui/graphicsview/qgraphicsitem.cpp | 38 +++++++++++++++++++++------------ src/gui/graphicsview/qgraphicsscene.cpp | 5 +++-- 2 files changed, 27 insertions(+), 16 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index b982393..bb95543 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -2511,10 +2511,10 @@ QTransform QGraphicsItem::sceneTransform() const QTransform m; if (d_ptr->hasTransform) { m = transform(); - m *= QTransform::fromTranslate(d_ptr->pos.x(), d_ptr->pos.y()); - } else { - // ### ? QTransform::fromTranslate(d_ptr->pos.x(), d_ptr->pos.y()) - m.translate(d_ptr->pos.x(), d_ptr->pos.y()); + if (!d_ptr->pos.isNull()) + m *= QTransform::fromTranslate(d_ptr->pos.x(), d_ptr->pos.y()); + } else if (!d_ptr->pos.isNull()) { + m = QTransform::fromTranslate(d_ptr->pos.x(), d_ptr->pos.y()); } // Combine with parent and add to cache. @@ -2639,6 +2639,8 @@ QTransform QGraphicsItem::itemTransform(const QGraphicsItem *other, bool *ok) co if (ok) *ok = true; const QPointF &itemPos = d_ptr->pos; + if (itemPos.isNull()) + return d_ptr->hasTransform ? transform() : QTransform(); if (d_ptr->hasTransform) return transform() * QTransform::fromTranslate(itemPos.x(), itemPos.y()); return QTransform::fromTranslate(itemPos.x(), itemPos.y()); @@ -2649,7 +2651,8 @@ QTransform QGraphicsItem::itemTransform(const QGraphicsItem *other, bool *ok) co const QPointF &otherPos = other->d_ptr->pos; if (other->d_ptr->hasTransform) { QTransform otherToParent = other->transform(); - otherToParent *= QTransform::fromTranslate(otherPos.x(), otherPos.y()); + if (!otherPos.isNull()) + otherToParent *= QTransform::fromTranslate(otherPos.x(), otherPos.y()); return otherToParent.inverted(ok); } else { if (ok) @@ -2674,11 +2677,11 @@ QTransform QGraphicsItem::itemTransform(const QGraphicsItem *other, bool *ok) co QTransform itemToParent = QTransform::fromTranslate(itemPos.x(), itemPos.y()); if (hasTr) - itemToParent = transform() * itemToParent; + itemToParent = itemPos.isNull() ? transform() : transform() * itemToParent; QTransform otherToParent = QTransform::fromTranslate(otherPos.x(), otherPos.y()); if (otherHasTr) - otherToParent = other->transform() * otherToParent; + otherToParent = otherPos.isNull() ? other->transform() : other->transform() * otherToParent; return itemToParent * otherToParent.inverted(ok); } @@ -2718,7 +2721,8 @@ QTransform QGraphicsItem::itemTransform(const QGraphicsItem *other, bool *ok) co const QGraphicsItemPrivate *pd = p->d_ptr; if (pd->hasTransform) x *= p->transform(); - x *= QTransform::fromTranslate(pd->pos.x(), pd->pos.y()); + if (!pd->pos.isNull()) + x *= QTransform::fromTranslate(pd->pos.x(), pd->pos.y()); } while ((p = p->d_ptr->parent) && p != root); if (parentOfOther) return x.inverted(ok); @@ -2995,7 +2999,9 @@ QRectF QGraphicsItem::childrenBoundingRect() const QRectF childRect; foreach (QGraphicsItem *child, children()) { QPointF childPos = child->pos(); - QTransform matrix = child->transform() * QTransform::fromTranslate(childPos.x(), childPos.y()); + QTransform matrix = child->transform(); + if (!childPos.isNull()) + matrix *= QTransform::fromTranslate(childPos.x(), childPos.y()); childRect |= matrix.mapRect(child->boundingRect() | child->childrenBoundingRect()); } return childRect; @@ -8544,13 +8550,17 @@ void QGraphicsItemGroup::addToGroup(QGraphicsItem *item) QTransform oldSceneMatrix = item->sceneTransform(); item->setPos(mapFromItem(item, 0, 0)); item->setParentItem(this); - item->setTransform(oldSceneMatrix - * sceneTransform().inverted() - * QTransform::fromTranslate(-item->x(), -item->y())); + QTransform newItemTransform(oldSceneMatrix); + newItemTransform *= sceneTransform().inverted(); + if (!item->pos().isNull()) + newItemTransform *= QTransform::fromTranslate(-item->x(), -item->y()); + item->setTransform(newItemTransform); item->d_func()->setIsMemberOfGroup(true); prepareGeometryChange(); - d->itemsBoundingRect |= (item->transform() * QTransform::fromTranslate(item->x(), item->y())) - .mapRect(item->boundingRect() | item->childrenBoundingRect()); + QTransform itemTransform(item->transform()); + if (!item->pos().isNull()) + itemTransform *= QTransform::fromTranslate(item->x(), item->y()); + d->itemsBoundingRect |= itemTransform.mapRect(item->boundingRect() | item->childrenBoundingRect()); update(); } diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index 9b06945..b509507 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -4772,8 +4772,9 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte if (itemCache->allExposed || !itemCache->exposed.isEmpty() || !scrollExposure.isEmpty()) { // Construct an item-to-pixmap transform. QPointF p = deviceRect.topLeft(); - QTransform itemToPixmap = QTransform::fromTranslate(-p.x(), -p.y()); - itemToPixmap = painter->worldTransform() * itemToPixmap; + QTransform itemToPixmap = painter->worldTransform(); + if (!p.isNull()) + itemToPixmap *= QTransform::fromTranslate(-p.x(), -p.y()); // Map the item's logical expose to pixmap coordinates. QRegion pixmapExposed = scrollExposure; -- cgit v0.12 From fac3c7b73ba2c6b39332445ae00b2fe26a578913 Mon Sep 17 00:00:00 2001 From: Bjoern Erik Nilsen Date: Mon, 2 Mar 2009 10:34:50 +0100 Subject: Fixes: Optimization: Important cut-offs for QTransform. Task: none RevBy: Samuel AutoTest: Still pass Details: Please do not perform (potentially expensive) calculations just for fun :) --- src/gui/painting/qtransform.cpp | 29 ++++++++++++++++++++++++++--- src/gui/painting/qtransform.h | 8 ++++++++ 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/src/gui/painting/qtransform.cpp b/src/gui/painting/qtransform.cpp index c120143..fa808d0 100644 --- a/src/gui/painting/qtransform.cpp +++ b/src/gui/painting/qtransform.cpp @@ -399,6 +399,9 @@ QTransform QTransform::inverted(bool *invertible) const */ QTransform & QTransform::translate(qreal dx, qreal dy) { + if (dx == 0 && dy == 0) + return *this; + switch(type()) { case TxNone: affine._dx = dx; @@ -435,7 +438,10 @@ QTransform & QTransform::translate(qreal dx, qreal dy) QTransform QTransform::fromTranslate(qreal dx, qreal dy) { QTransform transform(1, 0, 0, 1, dx, dy); - transform.m_dirty = TxTranslate; + if (dx == 0 && dy == 0) + transform.m_dirty = TxNone; + else + transform.m_dirty = TxTranslate; return transform; } @@ -447,6 +453,9 @@ QTransform QTransform::fromTranslate(qreal dx, qreal dy) */ QTransform & QTransform::scale(qreal sx, qreal sy) { + if (sx == 1 && sy == 1) + return *this; + switch(type()) { case TxNone: case TxTranslate: @@ -481,7 +490,10 @@ QTransform & QTransform::scale(qreal sx, qreal sy) QTransform QTransform::fromScale(qreal sx, qreal sy) { QTransform transform(sx, 0, 0, sy, 0, 0); - transform.m_dirty = TxScale; + if (sx == 1 && sy == 1) + transform.m_dirty = TxNone; + else + transform.m_dirty = TxScale; return transform; } @@ -544,6 +556,9 @@ const qreal inv_dist_to_plane = 1. / 1024.; */ QTransform & QTransform::rotate(qreal a, Qt::Axis axis) { + if (a == 0) + return *this; + qreal sina = 0; qreal cosa = 0; if (a == 90. || a == -270.) @@ -715,7 +730,15 @@ bool QTransform::operator!=(const QTransform &o) const */ QTransform & QTransform::operator*=(const QTransform &o) { - TransformationType t = qMax(type(), o.type()); + const TransformationType otherType = o.type(); + if (otherType == TxNone) + return *this; + + const TransformationType thisType = type(); + if (thisType == TxNone) + return operator=(o); + + TransformationType t = qMax(thisType, otherType); switch(t) { case TxNone: break; diff --git a/src/gui/painting/qtransform.h b/src/gui/painting/qtransform.h index de7ebcd..c76409b 100644 --- a/src/gui/painting/qtransform.h +++ b/src/gui/painting/qtransform.h @@ -257,6 +257,8 @@ inline qreal QTransform::dy() const inline QTransform &QTransform::operator*=(qreal num) { + if (num == 1.) + return *this; affine._m11 *= num; affine._m12 *= num; m_13 *= num; @@ -271,11 +273,15 @@ inline QTransform &QTransform::operator*=(qreal num) } inline QTransform &QTransform::operator/=(qreal div) { + if (div == 0) + return *this; div = 1/div; return operator*=(div); } inline QTransform &QTransform::operator+=(qreal num) { + if (num == 0) + return *this; affine._m11 += num; affine._m12 += num; m_13 += num; @@ -290,6 +296,8 @@ inline QTransform &QTransform::operator+=(qreal num) } inline QTransform &QTransform::operator-=(qreal num) { + if (num == 0) + return *this; affine._m11 -= num; affine._m12 -= num; m_13 -= num; -- cgit v0.12 From ab130a0019fadeff4622778ca9f8b3e630da14da Mon Sep 17 00:00:00 2001 From: Bjoern Erik Nilsen Date: Mon, 2 Mar 2009 16:22:20 +0100 Subject: Fixes: Speed up QGrahicsItemPrivate::effectiveOpacity(). RevBy: Andreas AutoTest: tst_QGraphicsItem::opacity still passes --- src/gui/graphicsview/qgraphicsitem.cpp | 12 +++++++++++- src/gui/graphicsview/qgraphicsitem_p.h | 2 ++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index bb95543..cda1bd1 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -1862,6 +1862,9 @@ qreal QGraphicsItem::opacity() const */ qreal QGraphicsItem::effectiveOpacity() const { + if (!d_ptr->hasEffectiveOpacity) + return qreal(1.0); + QVariant effectiveOpacity = d_ptr->extra(QGraphicsItemPrivate::ExtraEffectiveOpacity); return effectiveOpacity.isNull() ? qreal(1.0) : qreal(effectiveOpacity.toDouble()); } @@ -3680,7 +3683,14 @@ void QGraphicsItemPrivate::resolveEffectiveOpacity(qreal parentEffectiveOpacity) } // Set this item's resolved opacity. - setExtra(ExtraEffectiveOpacity, myEffectiveOpacity); + if (qFuzzyCompare(myEffectiveOpacity, qreal(1.0))) { + // Opaque, unset effective opacity. + hasEffectiveOpacity = 0; + unsetExtra(ExtraEffectiveOpacity); + } else { + hasEffectiveOpacity = 1; + setExtra(ExtraEffectiveOpacity, myEffectiveOpacity); + } // Resolve children always. for (int i = 0; i < children.size(); ++i) diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index 07f6958..98fe6ed 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -133,6 +133,7 @@ public: hasBoundingRegionGranularity(0), flags(0), hasOpacity(0), + hasEffectiveOpacity(0), isWidget(0), dirty(0), dirtyChildren(0), @@ -262,6 +263,7 @@ public: // New 32 bytes quint32 hasOpacity : 1; + quint32 hasEffectiveOpacity : 1; quint32 isWidget : 1; quint32 dirty : 1; quint32 dirtyChildren : 1; -- cgit v0.12 From 7f50f45da0ad4a9eedd3ad7d8a82f719f7f8dd73 Mon Sep 17 00:00:00 2001 From: Bjoern Erik Nilsen Date: Tue, 3 Mar 2009 13:06:05 +0100 Subject: Fixes: Optimize: QGraphicsItem::clipPath. RevBy: Andreas AutoTest: Still pass --- src/gui/graphicsview/qgraphicsitem.cpp | 46 +++++++++++----------------------- 1 file changed, 15 insertions(+), 31 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index cda1bd1..8b37648 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -3143,48 +3143,32 @@ QPainterPath QGraphicsItem::clipPath() const // Start with the item's bounding rect. clip.addRect(boundingRect()); - bool clipAway = false; if (d->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren) { - // Make list of parents up to the farthest ancestor that clips its - // children to its shape. - QVarLengthArray clippingAncestors; - const QGraphicsItem *parent = parentItem(); - const QGraphicsItem *clipOwner = 0; - do { + const QGraphicsItem *parent = this; + const QGraphicsItem *lastParent = this; + + // Intersect any in-between clips starting at the top and moving downwards. + while ((parent = parent->d_ptr->parent)) { if (parent->d_ptr->flags & ItemClipsChildrenToShape) { - clippingAncestors.append(parent); - clipOwner = parent; + // Map clip to the current parent and intersect with its shape. + clip = (lastParent->itemTransform(parent).map(clip)).intersected(parent->shape()); + if (clip.isEmpty()) + return clip; + lastParent = parent; } - } while ((parent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren) && (parent = parent->parentItem())); - - // Start with the topmost clip. - QPainterPath parentClip = clipOwner->shape(); - // Intersect any in-between clips starting at the bottom and moving - // upwards. - for (int i = clippingAncestors.size() - 2; i >= 0; --i) { - const QGraphicsItem *item = clippingAncestors[i]; - // ### what if itemtransform fails - if (clipOwner) - parentClip = clipOwner->itemTransform(item).map(parentClip); - parentClip = parentClip.intersected(item->shape()); - if (parentClip.isEmpty()) { - clip = parentClip; - clipAway = true; + if (!(parent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren)) break; - } - clipOwner = item; } - if (!clipAway) { + if (lastParent != this) { + // Map clip back to the item's transform. // ### what if itemtransform fails - clip = clip.intersected(clipOwner->itemTransform(this).map(parentClip)); - if (clip.isEmpty()) - clipAway = true; + clip = lastParent->itemTransform(this).map(clip); } } - if (!clipAway && d->flags & ItemClipsToShape) + if (d->flags & ItemClipsToShape) clip = clip.intersected(shape()); return clip; -- cgit v0.12 From b67dffcccea9166918ac93c281d87fd5eb3baf84 Mon Sep 17 00:00:00 2001 From: Bjoern Erik Nilsen Date: Tue, 3 Mar 2009 13:30:33 +0100 Subject: Fixes: Small optimization in QGraphicsItem::clipPath(). RevBy: Andreas Details: Use QPainterPath::addRect() rather than addPolygon() and closeSubPath(). --- src/gui/graphicsview/qgraphicsitem.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index 8b37648..fa77fd9 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -3259,8 +3259,8 @@ bool QGraphicsItem::collidesWithPath(const QPainterPath &path, Qt::ItemSelection return false; } - QRectF rectA = _q_adjustedRect(boundingRect()); - QRectF rectB = _q_adjustedRect(path.controlPointRect()); + const QRectF rectA = _q_adjustedRect(boundingRect()); + const QRectF rectB = _q_adjustedRect(path.controlPointRect()); if (!rectA.intersects(rectB)) { // This we can determine efficiently. If the two rects neither // intersect nor contain eachother, then the two items do not collide. @@ -3269,12 +3269,11 @@ bool QGraphicsItem::collidesWithPath(const QPainterPath &path, Qt::ItemSelection // For further testing, we need this item's shape or bounding rect. QPainterPath thisShape; - if (mode == Qt::IntersectsItemShape || mode == Qt::ContainsItemShape) { + if (mode == Qt::IntersectsItemShape || mode == Qt::ContainsItemShape) thisShape = (isClipped() && !d_ptr->localCollisionHack) ? clipPath() : shape(); - } else { - thisShape.addPolygon(_q_adjustedRect(boundingRect())); - thisShape.closeSubpath(); - } + else + thisShape.addRect(rectA); + if (thisShape == QPainterPath()) { // Empty shape? No collision. return false; -- cgit v0.12 From d74f1a91b05b943c1a8ae7847de6ee50b2093b89 Mon Sep 17 00:00:00 2001 From: Alexis Menard Date: Tue, 3 Mar 2009 17:08:30 +0100 Subject: Fixes: Be a bit more smarter when calling setGeometry from itemChange RevBy: bnilsen AutoTest: Bench Details : if we come from setPosHelper (so itemChange) we don't need to do all the stuff regarding the size in setGeometry because the size doesn't change. I remove two calls to fullUpdateHelper and update() because prepareGeometryChange already call updateHelper and setPosHelper call fullUpdaterHelper too so we don't need to call them inside setGeometry. We can only call prepareGeometryChange only if we don't come from setPos. --- src/gui/graphicsview/qgraphicsitem.cpp | 6 +-- src/gui/graphicsview/qgraphicsitem_p.h | 2 +- src/gui/graphicsview/qgraphicswidget.cpp | 58 ++++++++++++--------- src/gui/graphicsview/qgraphicswidget_p.h | 2 + .../benchmarks/qgraphicswidget/qgraphicswidget.pro | 6 +++ .../qgraphicswidget/tst_qgraphicswidget.cpp | 60 ++++++++++++++++++++++ 6 files changed, 105 insertions(+), 29 deletions(-) create mode 100644 tests/benchmarks/qgraphicswidget/qgraphicswidget.pro create mode 100644 tests/benchmarks/qgraphicswidget/tst_qgraphicswidget.cpp diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index fa77fd9..443cc8c 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -2352,7 +2352,7 @@ QPointF QGraphicsItem::scenePos() const the item is also updated; otherwise it is not updated before and after the change. */ -void QGraphicsItemPrivate::setPosHelper(const QPointF &pos, bool update) +void QGraphicsItemPrivate::setPosHelper(const QPointF &pos) { Q_Q(QGraphicsItem); if (this->pos == pos) @@ -2364,7 +2364,7 @@ void QGraphicsItemPrivate::setPosHelper(const QPointF &pos, bool update) return; // Update and repositition. - if (scene && update) { + if (scene) { fullUpdateHelper(true); q->prepareGeometryChange(); } @@ -2387,7 +2387,7 @@ void QGraphicsItemPrivate::setPosHelper(const QPointF &pos, bool update) */ void QGraphicsItem::setPos(const QPointF &pos) { - d_ptr->setPosHelper(pos, /* update = */ true); + d_ptr->setPosHelper(pos); } /*! diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index 98fe6ed..7deae52 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -158,7 +158,7 @@ public: virtual QVariant inputMethodQueryHelper(Qt::InputMethodQuery query) const; static bool movableAncestorIsSelected(const QGraphicsItem *item); - void setPosHelper(const QPointF &pos, bool update); + void setPosHelper(const QPointF &pos); void setVisibleHelper(bool newVisible, bool explicitly, bool update = true); void setEnabledHelper(bool newEnabled, bool explicitly, bool update = true); void updateHelper(const QRectF &rect = QRectF(), bool force = false); diff --git a/src/gui/graphicsview/qgraphicswidget.cpp b/src/gui/graphicsview/qgraphicswidget.cpp index 64ec0e7..7f02fb9 100644 --- a/src/gui/graphicsview/qgraphicswidget.cpp +++ b/src/gui/graphicsview/qgraphicswidget.cpp @@ -366,32 +366,33 @@ void QGraphicsWidget::resize(const QSizeF &size) void QGraphicsWidget::setGeometry(const QRectF &rect) { QGraphicsWidgetPrivate *wd = QGraphicsWidget::d_func(); - const QGraphicsLayoutItemPrivate *d = QGraphicsLayoutItem::d_ptr; - setAttribute(Qt::WA_Resized); - QRectF newGeom = rect; - newGeom.setSize(rect.size().expandedTo(effectiveSizeHint(Qt::MinimumSize)) - .boundedTo(effectiveSizeHint(Qt::MaximumSize))); - if (newGeom == d->geom) - return; - - // Update and prepare to change the geometry (remove from index). - if (wd->scene) { - if (rect.topLeft() != d->geom.topLeft()) - wd->fullUpdateHelper(true); - else - update(); - } - prepareGeometryChange(); - - // setPos triggers ItemPositionChange, which can adjust position + QGraphicsLayoutItemPrivate *d = QGraphicsLayoutItem::d_ptr; + QRectF newGeom; QPointF oldPos = d->geom.topLeft(); - wd->inSetGeometry = 1; - wd->setPosHelper(newGeom.topLeft(), /* update = */ false); - wd->inSetGeometry = 0; - newGeom.moveTopLeft(pos()); - - if (newGeom == d->geom) - return; + if (!wd->inSetPos) { + setAttribute(Qt::WA_Resized); + newGeom = rect; + newGeom.setSize(rect.size().expandedTo(effectiveSizeHint(Qt::MinimumSize)) + .boundedTo(effectiveSizeHint(Qt::MaximumSize))); + if (newGeom == d->geom) + return; + + // setPos triggers ItemPositionChange, which can adjust position + wd->inSetGeometry = 1; + wd->setPosHelper(newGeom.topLeft()); + wd->inSetGeometry = 0; + newGeom.moveTopLeft(pos()); + + if (newGeom == d->geom) + return; + + // Update and prepare to change the geometry (remove from index) if the size has changed. + if (wd->scene) { + if (rect.topLeft() == d->geom.topLeft()) { + prepareGeometryChange(); + } + } + } // Update the layout item geometry bool moved = oldPos != pos(); @@ -401,6 +402,11 @@ void QGraphicsWidget::setGeometry(const QRectF &rect) event.setOldPos(oldPos); event.setNewPos(pos()); QApplication::sendEvent(this, &event); + if (wd->inSetPos) { + //set the new pos + d->geom.moveTopLeft(pos()); + return; + } } QSizeF oldSize = size(); QGraphicsLayoutItem::setGeometry(newGeom); @@ -1016,9 +1022,11 @@ QVariant QGraphicsWidget::itemChange(GraphicsItemChange change, const QVariant & break; case ItemPositionHasChanged: if (!d->inSetGeometry) { + d->inSetPos = 1; // Ensure setGeometry is called (avoid recursion when setPos is // called from within setGeometry). setGeometry(QRectF(pos(), size())); + d->inSetPos = 0 ; } break; case ItemParentChange: { diff --git a/src/gui/graphicsview/qgraphicswidget_p.h b/src/gui/graphicsview/qgraphicswidget_p.h index 455a129..53eaa31 100644 --- a/src/gui/graphicsview/qgraphicswidget_p.h +++ b/src/gui/graphicsview/qgraphicswidget_p.h @@ -86,6 +86,7 @@ public: inheritedFontResolveMask(0), inSetGeometry(0), polished(0), + inSetPos(0), focusPolicy(Qt::NoFocus), focusNext(0), focusPrev(0), @@ -195,6 +196,7 @@ public: quint32 attributes : 10; quint32 inSetGeometry : 1; quint32 polished: 1; + quint32 inSetPos : 1; // Focus Qt::FocusPolicy focusPolicy; diff --git a/tests/benchmarks/qgraphicswidget/qgraphicswidget.pro b/tests/benchmarks/qgraphicswidget/qgraphicswidget.pro new file mode 100644 index 0000000..f1ec54e --- /dev/null +++ b/tests/benchmarks/qgraphicswidget/qgraphicswidget.pro @@ -0,0 +1,6 @@ +load(qttest_p4) +TEMPLATE = app +TARGET = tst_qgraphicswidget +TEMPLATE = app +# Input +SOURCES += tst_qgraphicswidget.cpp diff --git a/tests/benchmarks/qgraphicswidget/tst_qgraphicswidget.cpp b/tests/benchmarks/qgraphicswidget/tst_qgraphicswidget.cpp new file mode 100644 index 0000000..97837e2 --- /dev/null +++ b/tests/benchmarks/qgraphicswidget/tst_qgraphicswidget.cpp @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +****************************************************************************/ + +#include +#include +#include +#include +#include +//TESTED_FILES= + +class tst_QGraphicsWidget : public QObject +{ + Q_OBJECT + +public: + tst_QGraphicsWidget(); + virtual ~tst_QGraphicsWidget(); + +public slots: + void init(); + void cleanup(); + +private slots: + void move(); +}; + +tst_QGraphicsWidget::tst_QGraphicsWidget() +{ +} + +tst_QGraphicsWidget::~tst_QGraphicsWidget() +{ +} + +void tst_QGraphicsWidget::init() +{ +} + +void tst_QGraphicsWidget::cleanup() +{ +} + +void tst_QGraphicsWidget::move() +{ + QGraphicsScene scene; + QGraphicsWidget *widget = new QGraphicsWidget(); + scene.addItem(widget); + QGraphicsView view(&scene); + view.show(); + QBENCHMARK { + widget->setPos(qrand(),qrand()); + } +} + +QTEST_MAIN(tst_QGraphicsWidget) +#include "tst_qgraphicswidget.moc" -- cgit v0.12 From 0985805ab3c7de5b15c115a98afb15944b6d93b9 Mon Sep 17 00:00:00 2001 From: Alexis Menard Date: Mon, 9 Mar 2009 14:33:02 +0100 Subject: Fixes: Don't fill the pixmap because we will copy the cache into it. RevBy: bnilsen AutoTest: All pass + plasma ok --- src/gui/graphicsview/qgraphicsscene.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index b509507..8a67d24 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -4736,11 +4736,9 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte if (newCacheIndent != deviceData->cacheIndent || deviceRect.size() != pix.size()) { QPoint diff = newCacheIndent - deviceData->cacheIndent; QPixmap newPix(deviceRect.size()); - // ### Investigate removing this fill (test with Plasma and - // graphicssystem raster). - newPix.fill(Qt::transparent); if (!pix.isNull()) { QPainter newPixPainter(&newPix); + newPixPainter.setCompositionMode(QPainter::CompositionMode_Source); newPixPainter.drawPixmap(-diff, pix); newPixPainter.end(); } -- cgit v0.12 From 4556bcbd40c8feb7185aae7da5f0686f12d87565 Mon Sep 17 00:00:00 2001 From: Bjoern Erik Nilsen Date: Wed, 11 Mar 2009 17:24:41 +0100 Subject: Fixes: Optimization: Cache QGraphicsItem::clipPath(). RevBy: Alexis AutoTest: Still pass Details: No-brainer. --- src/gui/graphicsview/qgraphicsitem.cpp | 46 ++++++++++++++++++++++++++++------ src/gui/graphicsview/qgraphicsitem_p.h | 14 +++++++++++ 2 files changed, 53 insertions(+), 7 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index 443cc8c..5b997f4 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -631,6 +631,7 @@ void QGraphicsItemPrivate::updateAncestorFlag(QGraphicsItem::GraphicsItemFlag ch case QGraphicsItem::ItemClipsChildrenToShape: flag = AncestorClipsChildren; enabled = flags & QGraphicsItem::ItemClipsChildrenToShape; + invalidateCachedClipPathRecursively(/*childrenOnly=*/true); break; case QGraphicsItem::ItemIgnoresTransformations: flag = AncestorIgnoresTransformations; @@ -1270,6 +1271,9 @@ void QGraphicsItem::setFlags(GraphicsItemFlags flags) d_ptr->updateAncestorFlag(ItemClipsChildrenToShape); } + if ((flags & ItemClipsToShape) != (oldFlags & ItemClipsToShape)) + d_ptr->invalidateCachedClipPath(); + if ((flags & ItemIgnoresTransformations) != (oldFlags & ItemIgnoresTransformations)) { // Item children clipping changes. Propagate the ancestor flag to // all children. @@ -3136,10 +3140,15 @@ bool QGraphicsItem::isClipped() const QPainterPath QGraphicsItem::clipPath() const { Q_D(const QGraphicsItem); - QPainterPath clip; - if (!isClipped()) - return clip; + if (!d->dirtyClipPath) + return d->cachedClipPath; + + if (!isClipped()) { + d_ptr->setCachedClipPath(QPainterPath()); + return d->cachedClipPath; + } + QPainterPath clip; // Start with the item's bounding rect. clip.addRect(boundingRect()); @@ -3150,15 +3159,27 @@ QPainterPath QGraphicsItem::clipPath() const // Intersect any in-between clips starting at the top and moving downwards. while ((parent = parent->d_ptr->parent)) { if (parent->d_ptr->flags & ItemClipsChildrenToShape) { - // Map clip to the current parent and intersect with its shape. - clip = (lastParent->itemTransform(parent).map(clip)).intersected(parent->shape()); - if (clip.isEmpty()) + // Map clip to the current parent and intersect with its shape/clipPath + clip = lastParent->itemTransform(parent).map(clip); + if (!parent->d_ptr->dirtyClipPath) { + clip = clip.intersected(parent->d_ptr->cachedClipPath); + if (!(parent->d_ptr->flags & ItemClipsToShape)) + clip = clip.intersected(parent->shape()); + } else { + clip = clip.intersected(parent->shape()); + } + + if (clip.isEmpty()) { + d_ptr->setCachedClipPath(clip); return clip; + } lastParent = parent; } - if (!(parent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren)) + if (!(parent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren) + || !parent->d_ptr->dirtyClipPath) { break; + } } if (lastParent != this) { @@ -3171,6 +3192,7 @@ QPainterPath QGraphicsItem::clipPath() const if (d->flags & ItemClipsToShape) clip = clip.intersected(shape()); + d_ptr->setCachedClipPath(clip); return clip; } @@ -3726,6 +3748,15 @@ void QGraphicsItemPrivate::removeExtraItemCache() unsetExtra(ExtraCacheData); } +void QGraphicsItemPrivate::invalidateCachedClipPathRecursively(bool childrenOnly) +{ + if (!childrenOnly) + invalidateCachedClipPath(); + // ### Return if this item doesn't clip its children? + for (int i = 0; i < children.size(); ++i) + children.at(i)->d_ptr->invalidateCachedClipPathRecursively(false); +} + /*! \internal @@ -5505,6 +5536,7 @@ void QGraphicsItem::prepareGeometryChange() QGraphicsScenePrivate *scenePrivate = d_ptr->scene->d_func(); scenePrivate->removeFromIndex(this); + d_ptr->invalidateCachedClipPathRecursively(); } } diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index 7deae52..1e2c09b 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -138,6 +138,7 @@ public: dirty(0), dirtyChildren(0), localCollisionHack(0), + dirtyClipPath(1), globalStackingOrder(-1), sceneTransformIndex(-1), q_ptr(0) @@ -234,6 +235,18 @@ public: QGraphicsItemCache *extraItemCache() const; void removeExtraItemCache(); + inline void setCachedClipPath(const QPainterPath &path) + { + cachedClipPath = path; + dirtyClipPath = 0; + } + + inline void invalidateCachedClipPath() + { dirtyClipPath = 1; } + + void invalidateCachedClipPathRecursively(bool childrenOnly = false); + + QPainterPath cachedClipPath; QPointF pos; qreal z; QGraphicsScene *scene; @@ -268,6 +281,7 @@ public: quint32 dirty : 1; quint32 dirtyChildren : 1; quint32 localCollisionHack : 1; + quint32 dirtyClipPath : 1; // Optional stacking order int globalStackingOrder; -- cgit v0.12 From f4547b98b52bfc95fb0c14ec58df204cfcec0db2 Mon Sep 17 00:00:00 2001 From: Bjoern Erik Nilsen Date: Fri, 3 Apr 2009 14:19:12 +0200 Subject: Fixes: Cleanup/Optimize QGraphicsView::findItems. RevBy: Alexis AutoTest: Still pass Details: findItems() does almost exactly the same as QGraphicsView::items, the only difference is that it checks whether we are about to redraw all items. Next step is to optimize the items_helper functions. The patch does also include a fix for ::items/childItems_helper(const QPainterPath ...); it didn't take Qt::Intersects/ContainsItemBoundingRect into account (in the same fashion as we do in the other helper functions). --- src/gui/graphicsview/qgraphicsscene.cpp | 80 ++++++++++++++++----- src/gui/graphicsview/qgraphicsview.cpp | 122 ++++++++------------------------ src/gui/graphicsview/qgraphicsview_p.h | 7 +- 3 files changed, 94 insertions(+), 115 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index 8a67d24..3db8e35 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -1487,21 +1487,46 @@ QList QGraphicsScenePrivate::items_helper(const QPainterPath &p Qt::SortOrder order) const { QList items; + const QRectF pathRect = _q_adjustedRect(path.controlPointRect()); + // The index returns a rough estimate of what items are inside the rect. // Refine it by iterating through all returned items. - foreach (QGraphicsItem *item, estimateItemsInRect(_q_adjustedRect(path.controlPointRect()))) { + foreach (QGraphicsItem *item, estimateItemsInRect(pathRect)) { // Find the item's scene transform in a clever way. QTransform x = item->sceneTransform(); - bool ok; - QTransform xinv = x.inverted(&ok); - if (ok) { - QPainterPath mappedPath = xinv.map(path); - if (itemCollidesWithPath(item, mappedPath, mode)) { + bool keep = false; + + // ### _q_adjustedRect is only needed because QRectF::intersects, + // QRectF::contains and QTransform::map() and friends don't work with + // flat rectangles. + QRectF br = _q_adjustedRect(item->boundingRect()); + if (mode >= Qt::ContainsItemBoundingRect) { + // Path contains/intersects item's bounding rect + if ((mode == Qt::IntersectsItemBoundingRect && path.intersects(x.mapRect(br))) + || (mode == Qt::ContainsItemBoundingRect && path.contains(x.mapRect(br)))) { items << item; - if (item->flags() & QGraphicsItem::ItemClipsChildrenToShape) - childItems_helper(&items, item, mappedPath, mode); + keep = true; + } + } else { + // Path contains/intersects item's shape + if (QRectF_intersects(pathRect, x.mapRect(br))) { + bool ok; + QTransform xinv = x.inverted(&ok); + if (ok) { + if (itemCollidesWithPath(item, xinv.map(path), mode)) { + items << item; + keep = true; + } + } } } + + if (keep && (item->flags() & QGraphicsItem::ItemClipsChildrenToShape)) { + bool ok; + QTransform xinv = x.inverted(&ok); + if (ok) + childItems_helper(&items, item, xinv.map(path), mode); + } } if (order != Qt::SortOrder(-1)) @@ -1629,29 +1654,46 @@ void QGraphicsScenePrivate::childItems_helper(QList *items, Qt::ItemSelectionMode mode) const { bool parentClip = (parent->flags() & QGraphicsItem::ItemClipsChildrenToShape); - QPainterPath intersectedPath = !parentClip ? path : path.intersected(parent->shape()); - if (intersectedPath.isEmpty()) + QRectF pathRect = _q_adjustedRect(path.boundingRect()); + QRectF r = !parentClip ? pathRect : pathRect.intersected(_q_adjustedRect(parent->boundingRect())); + if (r.isEmpty()) return; QList &children = parent->d_ptr->children; for (int i = 0; i < children.size(); ++i) { QGraphicsItem *item = children.at(i); + if (item->d_ptr->hasTransform && !item->transform().isInvertible()) + continue; // Skip invisible items. if (!item->d_ptr->visible || qFuzzyCompare(item->effectiveOpacity(), qreal(0.0))) continue; - QTransform x = item->sceneTransform(); - - bool ok; - QTransform xinv = x.inverted(&ok); - if (ok) { - QPainterPath mappedPath = xinv.map(path); - if (itemCollidesWithPath(item, mappedPath, mode)) { + // ### _q_adjustedRect is only needed because QRectF::intersects, + // QRectF::contains and QTransform::map() and friends don't work with + // flat rectangles. + QRectF br = _q_adjustedRect(item->boundingRect()); + bool keep = false; + if (mode >= Qt::ContainsItemBoundingRect) { + // Polygon contains/intersects item's bounding rect + if ((mode == Qt::IntersectsItemBoundingRect && path.intersects(item->mapRectToParent(br))) + || (mode == Qt::ContainsItemBoundingRect && path.contains(item->mapRectToParent(br)))) { items->append(item); - if (!item->d_ptr->children.isEmpty()) - childItems_helper(items, item, mappedPath, mode); + keep = true; } + } else { + // Path contains/intersects item's shape + if (QRectF_intersects(pathRect, item->mapRectToParent(br))) { + if (itemCollidesWithPath(item, item->mapFromParent(path), mode)) { + items->append(item); + keep = true; + } + } + } + + if ((keep || !(item->flags() & QGraphicsItem::ItemClipsChildrenToShape)) && !item->d_ptr->children.isEmpty()) { + // Recurse into children that clip children. + childItems_helper(items, item, item->mapFromParent(path), mode); } } } diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp index f88918f..c421417 100644 --- a/src/gui/graphicsview/qgraphicsview.cpp +++ b/src/gui/graphicsview/qgraphicsview.cpp @@ -1029,103 +1029,40 @@ void QGraphicsViewPrivate::freeStyleOptionsArray(QStyleOptionGraphicsItem *array extern QPainterPath qt_regionToPath(const QRegion ®ion); -QList QGraphicsViewPrivate::findItems(const QRegion &exposedRegion, - const QTransform &worldTransform, - bool *allItems) const +QList QGraphicsViewPrivate::findItems(const QRegion &exposedRegion, bool *allItems) const { Q_Q(const QGraphicsView); - QList itemList; - QSet tmp; - bool simpleTransform = worldTransform.type() <= QTransform::TxScale; - - QPainterPath path = qt_regionToPath(exposedRegion); - *allItems = path.contains(q->mapFromScene(scene->d_func()->growingItemsBoundingRect).boundingRect()); - QList exposedRects; - QList exposedPolys; - - // Transform the exposed viewport rects to scene rects or polygons - foreach (const QRect &rect, exposedRegion.rects()) { - QPolygonF exposedPoly = q->mapToScene(rect.adjusted(-1, -1, 1, 1)); - QRectF exposedRect = exposedPoly.boundingRect(); - if (!simpleTransform) - exposedPolys << exposedPoly; - exposedRects << exposedRect; - } - - // Find which items need to be drawn. - if (*allItems) { + const QPainterPath exposedPath(qt_regionToPath(exposedRegion)); + const QPainterPath exposedScenePath(q->mapToScene(exposedPath)); + + if (exposedScenePath.contains(scene->d_func()->growingItemsBoundingRect)) { + Q_ASSERT(allItems); + *allItems = true; + // All items are guaranteed within the exposed region, don't bother using the index. - foreach (QGraphicsItem *item, scene->items()) { + QList itemList(scene->items()); + int i = 0; + while (i < itemList.size()) { // But we only want to include items that are visible - if (item->isVisible()) - itemList << item; - } - } else if (simpleTransform) { - // Simple rect lookups will do. - if (exposedRects.size() > 1) { - foreach (const QRectF &rect, exposedRects) { - foreach (QGraphicsItem *item, scene->d_func()->items_helper(rect, Qt::IntersectsItemBoundingRect, Qt::SortOrder(-1) /* don't sort */)) { - if (!tmp.contains(item)) { - tmp << item; - itemList << item; - } - } - } - } else { - itemList += scene->d_func()->items_helper(exposedRects[0], Qt::IntersectsItemBoundingRect, Qt::SortOrder(-1) /* don't sort */); - } - } else { - // Polygon lookup is necessary. - if (exposedRects.size() > 1) { - foreach (const QPolygonF &poly, exposedPolys) { - foreach (QGraphicsItem *item, scene->d_func()->items_helper(poly, Qt::IntersectsItemBoundingRect, Qt::SortOrder(-1) /* don't sort */)) { - if (!tmp.contains(item)) { - tmp << item; - itemList << item; - } - } - } - } else { - itemList += scene->d_func()->items_helper(exposedPolys[0], Qt::IntersectsItemBoundingRect, Qt::SortOrder(-1) /* don't sort */); + if (!itemList.at(i)->isVisible()) + itemList.removeAt(i); + else + ++i; } - } - // Check for items that ignore inherited transformations, and add them if - // necessary. - QRectF untr = scene->d_func()->largestUntransformableItem; - if (!*allItems && !untr.isNull()) { - // Map the largest untransformable item subtree boundingrect from view - // to scene coordinates, and use this to expand all exposed rects in - // search for untransformable items. - QRectF ltri = matrix.inverted().mapRect(untr); - ltri.adjust(-untr.width(), -untr.height(), untr.width(), untr.height()); - - foreach (const QRect &rect, exposedRegion.rects()) { - QRectF exposed = q->mapToScene(rect.adjusted(-1, -1, 1, 1)).boundingRect(); - exposed.adjust(-ltri.width(), -ltri.height(), ltri.width(), ltri.height()); - - foreach (QGraphicsItem *item, scene->d_func()->estimateItemsInRect(exposed)) { - if (item->d_ptr->itemIsUntransformable()) { - if (!tmp.contains(item)) { - QPainterPath rectPath; - rectPath.addRect(rect); - QPainterPath path = item->deviceTransform(q->viewportTransform()).inverted().map(rectPath); - if (item->collidesWithPath(path, Qt::IntersectsItemBoundingRect)) { - itemList << item; - tmp << item; - } - } - } - } - } + // Sort the items. + QGraphicsScenePrivate::sortItems(&itemList, Qt::DescendingOrder, scene->d_func()->sortCacheEnabled); + return itemList; } - tmp.clear(); - // Sort the items. - QGraphicsScenePrivate::sortItems(&itemList, Qt::DescendingOrder, - scene->d_func()->sortCacheEnabled); + if (scene->d_func()->largestUntransformableItem.isNull()) { + return scene->d_func()->items_helper(exposedScenePath, + Qt::IntersectsItemBoundingRect, + Qt::DescendingOrder); + } - return itemList; + // NB! Path must be in viewport coordinates. + return itemsInArea(exposedPath, Qt::IntersectsItemBoundingRect, Qt::DescendingOrder); } void QGraphicsViewPrivate::generateStyleOptions(const QList &itemList, @@ -2228,7 +2165,8 @@ QList QGraphicsView::items() const certainly room for improvement. */ QList QGraphicsViewPrivate::itemsInArea(const QPainterPath &path, - Qt::ItemSelectionMode mode) const + Qt::ItemSelectionMode mode, + Qt::SortOrder order) const { Q_Q(const QGraphicsView); @@ -2278,8 +2216,8 @@ QList QGraphicsViewPrivate::itemsInArea(const QPainterPath &pat } // ### Insertion sort would be faster. - QGraphicsScenePrivate::sortItems(&result, Qt::AscendingOrder, - scene->d_func()->sortCacheEnabled); + if (order != Qt::SortOrder(-1)) + QGraphicsScenePrivate::sortItems(&result, order, scene->d_func()->sortCacheEnabled); return result; } @@ -3485,7 +3423,7 @@ void QGraphicsView::paintEvent(QPaintEvent *event) // Find all exposed items bool allItems = false; - QList itemList = d->findItems(exposedRegion, viewTransform, &allItems); + QList itemList = d->findItems(exposedRegion, &allItems); #ifdef QGRAPHICSVIEW_DEBUG int exposedTime = stopWatch.elapsed(); diff --git a/src/gui/graphicsview/qgraphicsview_p.h b/src/gui/graphicsview/qgraphicsview_p.h index 2109673..a76279e 100644 --- a/src/gui/graphicsview/qgraphicsview_p.h +++ b/src/gui/graphicsview/qgraphicsview_p.h @@ -85,7 +85,8 @@ public: qint64 verticalScroll() const; QList itemsInArea(const QPainterPath &path, - Qt::ItemSelectionMode mode = Qt::IntersectsItemShape) const; + Qt::ItemSelectionMode mode = Qt::IntersectsItemShape, + Qt::SortOrder = Qt::AscendingOrder) const; QPointF mousePressItemPoint; QPointF mousePressScenePoint; @@ -172,9 +173,7 @@ public: void updateRegion(const QRegion ®ion); bool updateSceneSlotReimplementedChecked; - QList findItems(const QRegion &exposedRegion, - const QTransform &worldTransform, - bool *allItems) const; + QList findItems(const QRegion &exposedRegion, bool *allItems) const; void generateStyleOptions(const QList &itemList, QGraphicsItem **itemArray, -- cgit v0.12 From 4020327503eaefae42da4bd6e71125b6972ac97f Mon Sep 17 00:00:00 2001 From: Andreas Aardal Hanssen Date: Fri, 3 Apr 2009 14:43:11 +0200 Subject: Add a cut-off for simple rectangle lookups. Make sure we use the rect-variation of QGraphicsScene's item lookup functions if the view has a simple transform and a simple expose region. Reviewed-by: Bjoern Erik Nilsen --- src/gui/graphicsview/qgraphicsview.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp index c421417..9191fc5 100644 --- a/src/gui/graphicsview/qgraphicsview.cpp +++ b/src/gui/graphicsview/qgraphicsview.cpp @@ -1056,6 +1056,11 @@ QList QGraphicsViewPrivate::findItems(const QRegion &exposedReg } if (scene->d_func()->largestUntransformableItem.isNull()) { + if (exposedRegion.numRects() == 1 && matrix.type() <= QTransform::TxScale) { + return scene->d_func()->items_helper(exposedScenePath.controlPointRect(), + Qt::IntersectsItemBoundingRect, + Qt::DescendingOrder); + } return scene->d_func()->items_helper(exposedScenePath, Qt::IntersectsItemBoundingRect, Qt::DescendingOrder); -- cgit v0.12 From 4d019e66fb62d6f25627144539abd7f59413abee Mon Sep 17 00:00:00 2001 From: Bjoern Erik Nilsen Date: Tue, 17 Mar 2009 11:42:07 +0100 Subject: Fixes: Only use the parent's cached clip path if it is clipped. RevBy: TrustMe Details: ...otherwise it'll be empty and too much will be clipped away. --- src/gui/graphicsview/qgraphicsitem.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index 5b997f4..a3a12e7 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -3157,11 +3157,12 @@ QPainterPath QGraphicsItem::clipPath() const const QGraphicsItem *lastParent = this; // Intersect any in-between clips starting at the top and moving downwards. + bool foundValidClipPath = false; while ((parent = parent->d_ptr->parent)) { if (parent->d_ptr->flags & ItemClipsChildrenToShape) { // Map clip to the current parent and intersect with its shape/clipPath clip = lastParent->itemTransform(parent).map(clip); - if (!parent->d_ptr->dirtyClipPath) { + if ((foundValidClipPath = !parent->d_ptr->dirtyClipPath && parent->isClipped())) { clip = clip.intersected(parent->d_ptr->cachedClipPath); if (!(parent->d_ptr->flags & ItemClipsToShape)) clip = clip.intersected(parent->shape()); @@ -3177,7 +3178,7 @@ QPainterPath QGraphicsItem::clipPath() const } if (!(parent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren) - || !parent->d_ptr->dirtyClipPath) { + || foundValidClipPath) { break; } } -- cgit v0.12 From bd4b177e051852f0fb94df9c0ee2e512478e0d38 Mon Sep 17 00:00:00 2001 From: Bjoern Erik Nilsen Date: Wed, 18 Mar 2009 13:27:16 +0100 Subject: Fixes: Get rid of lots of calls to qFuzzyCompare. RevBy: Olivier AutoTest: Still pass. Details: Items usually don't have effective opacity, i.e. it is 1.0, so don't bother doing fuzzy compare if that's the case. --- src/gui/graphicsview/qgraphicsitem_p.h | 6 ++++++ src/gui/graphicsview/qgraphicsscene.cpp | 6 +++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index 1e2c09b..df07b87 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -246,6 +246,12 @@ public: void invalidateCachedClipPathRecursively(bool childrenOnly = false); + inline bool isInvisible() const + { + return !visible || (hasEffectiveOpacity + && qFuzzyCompare(q_func()->effectiveOpacity() + 1.0, qreal(1.0))); + } + QPainterPath cachedClipPath; QPointF pos; qreal z; diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index 3db8e35..1422184 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -1552,7 +1552,7 @@ void QGraphicsScenePrivate::childItems_helper(QList *items, continue; // Skip invisible items and all their children. - if (!item->d_ptr->visible || qFuzzyCompare(item->effectiveOpacity(), qreal(0.0))) + if (item->d_ptr->isInvisible()) continue; // ### _q_adjustedRect is only needed because QRectF::intersects, @@ -1612,7 +1612,7 @@ void QGraphicsScenePrivate::childItems_helper(QList *items, continue; // Skip invisible items. - if (!item->d_ptr->visible || qFuzzyCompare(item->effectiveOpacity() + 1, qreal(1.0))) + if (item->d_ptr->isInvisible()) continue; // ### _q_adjustedRect is only needed because QRectF::intersects, @@ -1666,7 +1666,7 @@ void QGraphicsScenePrivate::childItems_helper(QList *items, continue; // Skip invisible items. - if (!item->d_ptr->visible || qFuzzyCompare(item->effectiveOpacity(), qreal(0.0))) + if (item->d_ptr->isInvisible()) continue; // ### _q_adjustedRect is only needed because QRectF::intersects, -- cgit v0.12 From 5910dbe6e7a024301d431102703f9abe323ebd13 Mon Sep 17 00:00:00 2001 From: Bjoern Erik Nilsen Date: Thu, 19 Mar 2009 15:31:56 +0100 Subject: Fixes: Compile on funky scratchbox ARM compiler. --- src/gui/graphicsview/qgraphicsitem_p.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index df07b87..98e7c13 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -249,7 +249,7 @@ public: inline bool isInvisible() const { return !visible || (hasEffectiveOpacity - && qFuzzyCompare(q_func()->effectiveOpacity() + 1.0, qreal(1.0))); + && qFuzzyCompare(q_func()->effectiveOpacity() + 1, qreal(1.0))); } QPainterPath cachedClipPath; -- cgit v0.12 From c1909321a486621ef196dd4bb3cf354406d86d46 Mon Sep 17 00:00:00 2001 From: Bjoern Erik Nilsen Date: Fri, 20 Mar 2009 18:06:05 +0100 Subject: Fixes: Clever invalidating of the cached clip path. RevBy: Andreas AutoTest: still pass Details: Adds emptyClipPath bit, a cut-off to test if the item has an empty clip path (i.e., is clipped away). Also adds code for invalidating the cache from inside setPos(). --- src/gui/graphicsview/qgraphicsitem.cpp | 124 ++++++++++++++++++++++++++++++--- src/gui/graphicsview/qgraphicsitem_p.h | 18 ++++- 2 files changed, 129 insertions(+), 13 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index a3a12e7..badc41e 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -2368,15 +2368,18 @@ void QGraphicsItemPrivate::setPosHelper(const QPointF &pos) return; // Update and repositition. + inSetPosHelper = 1; if (scene) { fullUpdateHelper(true); q->prepareGeometryChange(); } this->pos = newPos; invalidateSceneTransformCache(); + updateCachedClipPathFromSetPosHelper(); // Send post-notification. q->itemChange(QGraphicsItem::ItemPositionHasChanged, newPos); + inSetPosHelper = 0; } /*! @@ -3141,7 +3144,7 @@ QPainterPath QGraphicsItem::clipPath() const { Q_D(const QGraphicsItem); if (!d->dirtyClipPath) - return d->cachedClipPath; + return d->emptyClipPath ? QPainterPath() : d->cachedClipPath; if (!isClipped()) { d_ptr->setCachedClipPath(QPainterPath()); @@ -3163,6 +3166,13 @@ QPainterPath QGraphicsItem::clipPath() const // Map clip to the current parent and intersect with its shape/clipPath clip = lastParent->itemTransform(parent).map(clip); if ((foundValidClipPath = !parent->d_ptr->dirtyClipPath && parent->isClipped())) { + if (parent->d_ptr->emptyClipPath) { + if (d_ptr->flags & ItemClipsChildrenToShape) + d_ptr->setEmptyCachedClipPathRecursively(); + else + d_ptr->setEmptyCachedClipPath(); + return QPainterPath(); + } clip = clip.intersected(parent->d_ptr->cachedClipPath); if (!(parent->d_ptr->flags & ItemClipsToShape)) clip = clip.intersected(parent->shape()); @@ -3171,7 +3181,10 @@ QPainterPath QGraphicsItem::clipPath() const } if (clip.isEmpty()) { - d_ptr->setCachedClipPath(clip); + if (d_ptr->flags & ItemClipsChildrenToShape) + d_ptr->setEmptyCachedClipPathRecursively(); + else + d_ptr->setEmptyCachedClipPath(); return clip; } lastParent = parent; @@ -3749,13 +3762,95 @@ void QGraphicsItemPrivate::removeExtraItemCache() unsetExtra(ExtraCacheData); } -void QGraphicsItemPrivate::invalidateCachedClipPathRecursively(bool childrenOnly) +void QGraphicsItemPrivate::setEmptyCachedClipPathRecursively(const QRectF &emptyIfOutsideThisRect) +{ + setEmptyCachedClipPath(); + + const bool checkRect = !emptyIfOutsideThisRect.isNull() + && !(flags & QGraphicsItem::ItemClipsChildrenToShape); + for (int i = 0; i < children.size(); ++i) { + if (!checkRect) { + children.at(i)->d_ptr->setEmptyCachedClipPathRecursively(); + continue; + } + + QGraphicsItem *child = children.at(i); + const QRectF rect = child->mapRectFromParent(emptyIfOutsideThisRect); + if (rect.intersects(child->boundingRect())) + child->d_ptr->invalidateCachedClipPathRecursively(false, rect); + else + child->d_ptr->setEmptyCachedClipPathRecursively(rect); + } +} + +void QGraphicsItemPrivate::invalidateCachedClipPathRecursively(bool childrenOnly, const QRectF &emptyIfOutsideThisRect) { if (!childrenOnly) invalidateCachedClipPath(); - // ### Return if this item doesn't clip its children? - for (int i = 0; i < children.size(); ++i) - children.at(i)->d_ptr->invalidateCachedClipPathRecursively(false); + + const bool checkRect = !emptyIfOutsideThisRect.isNull(); + for (int i = 0; i < children.size(); ++i) { + if (!checkRect) { + children.at(i)->d_ptr->invalidateCachedClipPathRecursively(false); + continue; + } + + QGraphicsItem *child = children.at(i); + const QRectF rect = child->mapRectFromParent(emptyIfOutsideThisRect); + if (rect.intersects(child->boundingRect())) + child->d_ptr->invalidateCachedClipPathRecursively(false, rect); + else + child->d_ptr->setEmptyCachedClipPathRecursively(rect); + } +} + +void QGraphicsItemPrivate::updateCachedClipPathFromSetPosHelper() +{ + Q_ASSERT(inSetPosHelper); + + if (!(ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren)) + return; // Not clipped by any ancestor. + + // Find closest clip ancestor. + QGraphicsItem *clipParent = parent; + while (clipParent && !(clipParent->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape)) + clipParent = clipParent->d_ptr->parent; + + Q_ASSERT(clipParent); + Q_Q(QGraphicsItem); + + // From here everything is calculated in clip parent's coordinates. + const QTransform thisToParentTransform(q->itemTransform(clipParent)); + const QRectF parentBoundingRect(clipParent->boundingRect()); + const QRectF thisBoundingRect(thisToParentTransform.mapRect(q->boundingRect())); + + if (!parentBoundingRect.intersects(thisBoundingRect)) { + // Item is moved outside the clip parent's bounding rect, + // i.e. it is fully clipped and the clip path is empty. + if (flags & QGraphicsItem::ItemClipsChildrenToShape) + setEmptyCachedClipPathRecursively(); + else + setEmptyCachedClipPathRecursively(thisToParentTransform.inverted().mapRect(parentBoundingRect)); + return; + } + + const QPainterPath parentClip(clipParent->isClipped() ? clipParent->clipPath() : clipParent->shape()); + if (parentClip.contains(thisBoundingRect)) + return; // Item is inside the clip parent's shape. No update required. + + const QRectF parentClipRect(parentClip.controlPointRect()); + if (!parentClipRect.intersects(thisBoundingRect)) { + // Item is moved outside the clip parent's shape, + // i.e. it is fully clipped and the clip path is empty. + if (flags & QGraphicsItem::ItemClipsChildrenToShape) + setEmptyCachedClipPathRecursively(); + else + setEmptyCachedClipPathRecursively(thisToParentTransform.inverted().mapRect(parentClipRect)); + } else { + // Item is partially inside the clip parent's shape, + // i.e. the cached clip path must be invalidated. + invalidateCachedClipPathRecursively(false, thisToParentTransform.inverted().mapRect(parentClipRect)); + } } /*! @@ -5532,13 +5627,20 @@ void QGraphicsItem::removeFromIndex() */ void QGraphicsItem::prepareGeometryChange() { - if (d_ptr->scene) { - d_ptr->updateHelper(); + if (!d_ptr->scene) + return; + + d_ptr->updateHelper(); + QGraphicsScenePrivate *scenePrivate = d_ptr->scene->d_func(); + scenePrivate->removeFromIndex(this); - QGraphicsScenePrivate *scenePrivate = d_ptr->scene->d_func(); - scenePrivate->removeFromIndex(this); + if (d_ptr->inSetPosHelper) + return; + + if (d_ptr->flags & ItemClipsChildrenToShape) d_ptr->invalidateCachedClipPathRecursively(); - } + else + d_ptr->invalidateCachedClipPath(); } /*! diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index 98e7c13..f5c3505 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -139,6 +139,8 @@ public: dirtyChildren(0), localCollisionHack(0), dirtyClipPath(1), + emptyClipPath(0), + inSetPosHelper(0), globalStackingOrder(-1), sceneTransformIndex(-1), q_ptr(0) @@ -239,12 +241,22 @@ public: { cachedClipPath = path; dirtyClipPath = 0; + emptyClipPath = 0; } + inline void setEmptyCachedClipPath() + { + emptyClipPath = 1; + dirtyClipPath = 0; + } + + void setEmptyCachedClipPathRecursively(const QRectF &emptyIfOutsideThisRect = QRectF()); + inline void invalidateCachedClipPath() - { dirtyClipPath = 1; } + { /*static int count = 0 ;qWarning("%i", ++count);*/ dirtyClipPath = 1; emptyClipPath = 0; } - void invalidateCachedClipPathRecursively(bool childrenOnly = false); + void invalidateCachedClipPathRecursively(bool childrenOnly = false, const QRectF &emptyIfOutsideThisRect = QRectF()); + void updateCachedClipPathFromSetPosHelper(); inline bool isInvisible() const { @@ -288,6 +300,8 @@ public: quint32 dirtyChildren : 1; quint32 localCollisionHack : 1; quint32 dirtyClipPath : 1; + quint32 emptyClipPath : 1; + quint32 inSetPosHelper : 1; // Optional stacking order int globalStackingOrder; -- cgit v0.12 From 95fa7a93bc840e0f49ee30e76abb2b4f8579c997 Mon Sep 17 00:00:00 2001 From: Bjoern Erik Nilsen Date: Mon, 23 Mar 2009 15:54:30 +0100 Subject: Fixes: Optimization: Clip path is empty if the bounding rect is empty. RevBy: TrustMe --- src/gui/graphicsview/qgraphicsitem.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index badc41e..75b6cf1 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -3151,9 +3151,18 @@ QPainterPath QGraphicsItem::clipPath() const return d->cachedClipPath; } + const QRectF thisBoundingRect(boundingRect()); + if (thisBoundingRect.isEmpty()) { + if (d_ptr->flags & ItemClipsChildrenToShape) + d_ptr->setEmptyCachedClipPathRecursively(); + else + d_ptr->setEmptyCachedClipPath(); + return QPainterPath(); + } + QPainterPath clip; // Start with the item's bounding rect. - clip.addRect(boundingRect()); + clip.addRect(thisBoundingRect); if (d->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren) { const QGraphicsItem *parent = this; -- cgit v0.12 From deccc867b244fbc52ca58e21623febbc27310b05 Mon Sep 17 00:00:00 2001 From: Bjoern Erik Nilsen Date: Mon, 23 Mar 2009 19:37:41 +0100 Subject: Fixes: Don't bother processing items that are clipped away. RevBy: Andreas --- src/gui/graphicsview/qgraphicsitem_p.h | 3 + src/gui/graphicsview/qgraphicsscene.cpp | 116 ++++++++++++++++++-------------- 2 files changed, 67 insertions(+), 52 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index f5c3505..3e4c269 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -264,6 +264,9 @@ public: && qFuzzyCompare(q_func()->effectiveOpacity() + 1, qreal(1.0))); } + inline bool isClippedAway() const + { return !dirtyClipPath && q_func()->isClipped() && (emptyClipPath || cachedClipPath.isEmpty()); } + QPainterPath cachedClipPath; QPointF pos; qreal z; diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index 1422184..f32fe71 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -1539,12 +1539,14 @@ void QGraphicsScenePrivate::childItems_helper(QList *items, const QRectF &rect, Qt::ItemSelectionMode mode) const { - QPainterPath path; bool parentClip = (parent->flags() & QGraphicsItem::ItemClipsChildrenToShape); + if (parentClip && parent->d_ptr->isClippedAway()) + return; QRectF r = !parentClip ? _q_adjustedRect(rect) : _q_adjustedRect(rect).intersected(_q_adjustedRect(parent->boundingRect())); if (r.isEmpty()) return; + QPainterPath path; QList &children = parent->d_ptr->children; for (int i = 0; i < children.size(); ++i) { QGraphicsItem *item = children.at(i); @@ -1555,28 +1557,30 @@ void QGraphicsScenePrivate::childItems_helper(QList *items, if (item->d_ptr->isInvisible()) continue; - // ### _q_adjustedRect is only needed because QRectF::intersects, - // QRectF::contains and QTransform::map() and friends don't work with - // flat rectangles. - QRectF br = _q_adjustedRect(item->boundingRect()); - QRectF mbr = item->mapRectToParent(br); bool keep = false; - if (mode >= Qt::ContainsItemBoundingRect) { - // Rect intersects/contains item's bounding rect - if ((mode == Qt::IntersectsItemBoundingRect && QRectF_intersects(rect, mbr)) - || (mode == Qt::ContainsItemBoundingRect && rect != mbr && rect.contains(br))) { - items->append(item); - keep = true; - } - } else { - // Rect intersects/contains item's shape - if (QRectF_intersects(rect, mbr)) { - if (path == QPainterPath()) - path.addRect(rect); - if (itemCollidesWithPath(item, item->mapFromParent(path), mode)) { + if (!item->d_ptr->isClippedAway()) { + // ### _q_adjustedRect is only needed because QRectF::intersects, + // QRectF::contains and QTransform::map() and friends don't work with + // flat rectangles. + QRectF br = _q_adjustedRect(item->boundingRect()); + QRectF mbr = item->mapRectToParent(br); + if (mode >= Qt::ContainsItemBoundingRect) { + // Rect intersects/contains item's bounding rect + if ((mode == Qt::IntersectsItemBoundingRect && QRectF_intersects(rect, mbr)) + || (mode == Qt::ContainsItemBoundingRect && rect != mbr && rect.contains(br))) { items->append(item); keep = true; } + } else { + // Rect intersects/contains item's shape + if (QRectF_intersects(rect, mbr)) { + if (path == QPainterPath()) + path.addRect(rect); + if (itemCollidesWithPath(item, item->mapFromParent(path), mode)) { + items->append(item); + keep = true; + } + } } } @@ -1598,13 +1602,15 @@ void QGraphicsScenePrivate::childItems_helper(QList *items, const QPolygonF &polygon, Qt::ItemSelectionMode mode) const { - QPainterPath path; bool parentClip = (parent->flags() & QGraphicsItem::ItemClipsChildrenToShape); + if (parentClip && parent->d_ptr->isClippedAway()) + return; QRectF polyRect = _q_adjustedRect(polygon.boundingRect()); QRectF r = !parentClip ? polyRect : polyRect.intersected(_q_adjustedRect(parent->boundingRect())); if (r.isEmpty()) return; + QPainterPath path; QList &children = parent->d_ptr->children; for (int i = 0; i < children.size(); ++i) { QGraphicsItem *item = children.at(i); @@ -1615,29 +1621,31 @@ void QGraphicsScenePrivate::childItems_helper(QList *items, if (item->d_ptr->isInvisible()) continue; - // ### _q_adjustedRect is only needed because QRectF::intersects, - // QRectF::contains and QTransform::map() and friends don't work with - // flat rectangles. - QRectF br = _q_adjustedRect(item->boundingRect()); bool keep = false; - if (mode >= Qt::ContainsItemBoundingRect) { - // Polygon contains/intersects item's bounding rect - if (path == QPainterPath()) - path.addPolygon(polygon); - if ((mode == Qt::IntersectsItemBoundingRect && path.intersects(item->mapRectToParent(br))) - || (mode == Qt::ContainsItemBoundingRect && path.contains(item->mapRectToParent(br)))) { - items->append(item); - keep = true; - } - } else { - // Polygon contains/intersects item's shape - if (QRectF_intersects(polyRect, item->mapRectToParent(br))) { + if (!item->d_ptr->isClippedAway()) { + // ### _q_adjustedRect is only needed because QRectF::intersects, + // QRectF::contains and QTransform::map() and friends don't work with + // flat rectangles. + QRectF br = _q_adjustedRect(item->boundingRect()); + if (mode >= Qt::ContainsItemBoundingRect) { + // Polygon contains/intersects item's bounding rect if (path == QPainterPath()) path.addPolygon(polygon); - if (itemCollidesWithPath(item, item->mapFromParent(path), mode)) { + if ((mode == Qt::IntersectsItemBoundingRect && path.intersects(item->mapRectToParent(br))) + || (mode == Qt::ContainsItemBoundingRect && path.contains(item->mapRectToParent(br)))) { items->append(item); keep = true; } + } else { + // Polygon contains/intersects item's shape + if (QRectF_intersects(polyRect, item->mapRectToParent(br))) { + if (path == QPainterPath()) + path.addPolygon(polygon); + if (itemCollidesWithPath(item, item->mapFromParent(path), mode)) { + items->append(item); + keep = true; + } + } } } @@ -1654,6 +1662,8 @@ void QGraphicsScenePrivate::childItems_helper(QList *items, Qt::ItemSelectionMode mode) const { bool parentClip = (parent->flags() & QGraphicsItem::ItemClipsChildrenToShape); + if (parentClip && parent->d_ptr->isClippedAway()) + return; QRectF pathRect = _q_adjustedRect(path.boundingRect()); QRectF r = !parentClip ? pathRect : pathRect.intersected(_q_adjustedRect(parent->boundingRect())); if (r.isEmpty()) @@ -1669,25 +1679,27 @@ void QGraphicsScenePrivate::childItems_helper(QList *items, if (item->d_ptr->isInvisible()) continue; - // ### _q_adjustedRect is only needed because QRectF::intersects, - // QRectF::contains and QTransform::map() and friends don't work with - // flat rectangles. - QRectF br = _q_adjustedRect(item->boundingRect()); bool keep = false; - if (mode >= Qt::ContainsItemBoundingRect) { - // Polygon contains/intersects item's bounding rect - if ((mode == Qt::IntersectsItemBoundingRect && path.intersects(item->mapRectToParent(br))) - || (mode == Qt::ContainsItemBoundingRect && path.contains(item->mapRectToParent(br)))) { - items->append(item); - keep = true; - } - } else { - // Path contains/intersects item's shape - if (QRectF_intersects(pathRect, item->mapRectToParent(br))) { - if (itemCollidesWithPath(item, item->mapFromParent(path), mode)) { + if (!item->d_ptr->isClippedAway()) { + // ### _q_adjustedRect is only needed because QRectF::intersects, + // QRectF::contains and QTransform::map() and friends don't work with + // flat rectangles. + QRectF br = _q_adjustedRect(item->boundingRect()); + if (mode >= Qt::ContainsItemBoundingRect) { + // Polygon contains/intersects item's bounding rect + if ((mode == Qt::IntersectsItemBoundingRect && path.intersects(item->mapRectToParent(br))) + || (mode == Qt::ContainsItemBoundingRect && path.contains(item->mapRectToParent(br)))) { items->append(item); keep = true; } + } else { + // Path contains/intersects item's shape + if (QRectF_intersects(pathRect, item->mapRectToParent(br))) { + if (itemCollidesWithPath(item, item->mapFromParent(path), mode)) { + items->append(item); + keep = true; + } + } } } -- cgit v0.12 From 0d959a6c402ea3a3a55d7076d453d4bdbf8dce8e Mon Sep 17 00:00:00 2001 From: Bjoern Erik Nilsen Date: Tue, 24 Mar 2009 15:50:26 +0100 Subject: Fixes: Discard update requests if possible. AutoTest: Still pass. Details: Update requests can be discarded if the item itself is clipped away and the item clips all its children to shape. This cut-off is extremely effective (and aggressive:)) --- src/gui/graphicsview/qgraphicsitem.cpp | 54 ++++++++++++++++++++++------------ src/gui/graphicsview/qgraphicsitem_p.h | 9 ++++-- src/gui/graphicsview/qgraphicsview.cpp | 2 ++ 3 files changed, 44 insertions(+), 21 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index 75b6cf1..a5d6021 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -1063,7 +1063,7 @@ void QGraphicsItem::setParentItem(QGraphicsItem *parent) qVariantSetValue(variant, this); d_ptr->parent->itemChange(ItemChildAddedChange, variant); if (!implicitUpdate) - d_ptr->updateHelper(); + d_ptr->updateHelper(QRectF(), false, true); // Inherit ancestor flags from the new parent. d_ptr->updateAncestorFlag(QGraphicsItem::GraphicsItemFlag(-1)); @@ -1092,7 +1092,7 @@ void QGraphicsItem::setParentItem(QGraphicsItem *parent) if (!d_ptr->enabled && !d_ptr->explicitlyDisabled) d_ptr->setEnabledHelper(true, /* explicit = */ false); - d_ptr->updateHelper(); + d_ptr->updateHelper(QRectF(), false, true); } if (d_ptr->scene) { @@ -1236,7 +1236,7 @@ void QGraphicsItem::setFlags(GraphicsItemFlags flags) int geomChangeFlagsMask = (ItemClipsChildrenToShape | ItemClipsToShape | ItemIgnoresTransformations); bool fullUpdate = (flags & geomChangeFlagsMask) != (d_ptr->flags & geomChangeFlagsMask); if (fullUpdate) - d_ptr->fullUpdateHelper(); + d_ptr->fullUpdateHelper(false, true); // Keep the old flags to compare the diff. GraphicsItemFlags oldFlags = this->flags(); @@ -1281,7 +1281,7 @@ void QGraphicsItem::setFlags(GraphicsItemFlags flags) } // ### Why updateHelper? - d_ptr->updateHelper(); + d_ptr->updateHelper(QRectF(), false, true); // Notify change. itemChange(ItemFlagsHaveChanged, quint32(flags)); @@ -2369,13 +2369,13 @@ void QGraphicsItemPrivate::setPosHelper(const QPointF &pos) // Update and repositition. inSetPosHelper = 1; + updateCachedClipPathFromSetPosHelper(newPos); if (scene) { fullUpdateHelper(true); q->prepareGeometryChange(); } this->pos = newPos; invalidateSceneTransformCache(); - updateCachedClipPathFromSetPosHelper(); // Send post-notification. q->itemChange(QGraphicsItem::ItemPositionHasChanged, newPos); @@ -2771,7 +2771,7 @@ void QGraphicsItem::setMatrix(const QMatrix &matrix, bool combine) return; // Update and set the new transformation. - d_ptr->fullUpdateHelper(true); + d_ptr->fullUpdateHelper(true, true); prepareGeometryChange(); d_ptr->hasTransform = !newTransform.isIdentity(); d_ptr->setExtra(QGraphicsItemPrivate::ExtraTransform, newTransform); @@ -2817,7 +2817,7 @@ void QGraphicsItem::setTransform(const QTransform &matrix, bool combine) return; // Update and set the new transformation. - d_ptr->fullUpdateHelper(true); + d_ptr->fullUpdateHelper(true, true); prepareGeometryChange(); d_ptr->hasTransform = !newTransform.isIdentity(); d_ptr->setExtra(QGraphicsItemPrivate::ExtraTransform, newTransform); @@ -3626,7 +3626,7 @@ void QGraphicsItem::setBoundingRegionGranularity(qreal granularity) only case where the item's background should be marked as dirty even when the item isn't visible. */ -void QGraphicsItemPrivate::updateHelper(const QRectF &rect, bool force) +void QGraphicsItemPrivate::updateHelper(const QRectF &rect, bool force, bool maybeDirtyClipPath) { // No scene, or if the scene is updating everything, means we have nothing // to do. The only exception is if the scene tracks the growing scene rect. @@ -3634,6 +3634,8 @@ void QGraphicsItemPrivate::updateHelper(const QRectF &rect, bool force) return; if (!scene || (scene && scene->d_func()->updateAll && scene->d_func()->hasSceneRect)) return; + if (!force && !maybeDirtyClipPath && discardUpdateRequest()) + return; if (scene && (visible || force)) { if (rect.isNull()) dirty = 1; @@ -3646,17 +3648,19 @@ void QGraphicsItemPrivate::updateHelper(const QRectF &rect, bool force) Propagates updates to \a item and all its children. */ -void QGraphicsItemPrivate::fullUpdateHelper(bool childrenOnly) +void QGraphicsItemPrivate::fullUpdateHelper(bool childrenOnly, bool maybeDirtyClipPath) { + if (!maybeDirtyClipPath && discardUpdateRequest()) + return; // No scene, or if the scene is updating everything, means we have nothing // to do. The only exception is if the scene tracks the growing scene rect. if (!scene || (scene && scene->d_func()->updateAll && scene->d_func()->hasSceneRect)) return; if (!childrenOnly && !dirty) - updateHelper(); + updateHelper(QRectF(), false, maybeDirtyClipPath); if (children.isEmpty() || dirtyChildren) return; - if (flags & QGraphicsItem::ItemClipsChildrenToShape) { + if (flags & QGraphicsItem::ItemClipsChildrenToShape || children.isEmpty()) { // ### mark all children dirty? // Unnecessary to update children as well. return; @@ -3683,7 +3687,7 @@ void QGraphicsItemPrivate::fullUpdateHelper(bool childrenOnly) } } foreach (QGraphicsItem *child, children) - child->d_ptr->fullUpdateHelper(); + child->d_ptr->fullUpdateHelper(false, maybeDirtyClipPath); dirtyChildren = 1; } @@ -3813,23 +3817,35 @@ void QGraphicsItemPrivate::invalidateCachedClipPathRecursively(bool childrenOnly } } -void QGraphicsItemPrivate::updateCachedClipPathFromSetPosHelper() +void QGraphicsItemPrivate::updateCachedClipPathFromSetPosHelper(const QPointF &newPos) { Q_ASSERT(inSetPosHelper); if (!(ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren)) return; // Not clipped by any ancestor. - // Find closest clip ancestor. + // Find closest clip ancestor and transform. + Q_Q(QGraphicsItem); + QTransform thisToParentTransform = hasTransform + ? q->transform() * QTransform::fromTranslate(newPos.x(), newPos.y()) + : QTransform::fromTranslate(newPos.x(), newPos.y()); QGraphicsItem *clipParent = parent; - while (clipParent && !(clipParent->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape)) + while (clipParent && !(clipParent->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape)) { + if (clipParent->d_ptr->hasTransform) + thisToParentTransform *= clipParent->transform(); + if (!clipParent->d_ptr->pos.isNull()) { + thisToParentTransform *= QTransform::fromTranslate(clipParent->d_ptr->pos.x(), + clipParent->d_ptr->pos.y()); + } clipParent = clipParent->d_ptr->parent; + } + // thisToParentTransform is now the same as q->itemTransform(clipParent), except + // that the new position (which is not yet set on the item) is taken into account. Q_ASSERT(clipParent); - Q_Q(QGraphicsItem); + Q_ASSERT(clipParent->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape); // From here everything is calculated in clip parent's coordinates. - const QTransform thisToParentTransform(q->itemTransform(clipParent)); const QRectF parentBoundingRect(clipParent->boundingRect()); const QRectF thisBoundingRect(thisToParentTransform.mapRect(q->boundingRect())); @@ -3894,6 +3910,8 @@ void QGraphicsItem::update(const QRectF &rect) { if (d_ptr->dirty || (rect.isEmpty() && !rect.isNull())) return; + if (d_ptr->discardUpdateRequest()) + return; if (d_ptr->scene && isVisible()) { if (CacheMode(d_ptr->cacheMode) != NoCache) { QGraphicsItemCache *cache = d_ptr->extraItemCache(); @@ -5639,7 +5657,7 @@ void QGraphicsItem::prepareGeometryChange() if (!d_ptr->scene) return; - d_ptr->updateHelper(); + d_ptr->updateHelper(QRectF(), false, /*maybeDirtyClipPath=*/!d_ptr->inSetPosHelper); QGraphicsScenePrivate *scenePrivate = d_ptr->scene->d_func(); scenePrivate->removeFromIndex(this); diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index 3e4c269..dabbe53 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -164,8 +164,8 @@ public: void setPosHelper(const QPointF &pos); void setVisibleHelper(bool newVisible, bool explicitly, bool update = true); void setEnabledHelper(bool newEnabled, bool explicitly, bool update = true); - void updateHelper(const QRectF &rect = QRectF(), bool force = false); - void fullUpdateHelper(bool childrenOnly = false); + void updateHelper(const QRectF &rect = QRectF(), bool force = false, bool maybeDirtyClipPath = false); + void fullUpdateHelper(bool childrenOnly = false, bool maybeDirtyClipPath = false); void resolveEffectiveOpacity(qreal effectiveParentOpacity); void resolveDepth(int parentDepth); void invalidateSceneTransformCache(); @@ -256,7 +256,7 @@ public: { /*static int count = 0 ;qWarning("%i", ++count);*/ dirtyClipPath = 1; emptyClipPath = 0; } void invalidateCachedClipPathRecursively(bool childrenOnly = false, const QRectF &emptyIfOutsideThisRect = QRectF()); - void updateCachedClipPathFromSetPosHelper(); + void updateCachedClipPathFromSetPosHelper(const QPointF &newPos); inline bool isInvisible() const { @@ -267,6 +267,9 @@ public: inline bool isClippedAway() const { return !dirtyClipPath && q_func()->isClipped() && (emptyClipPath || cachedClipPath.isEmpty()); } + inline bool discardUpdateRequest() const + { return ((flags & QGraphicsItem::ItemClipsChildrenToShape) || children.isEmpty()) && isClippedAway(); } + QPainterPath cachedClipPath; QPointF pos; qreal z; diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp index 9191fc5..43263da 100644 --- a/src/gui/graphicsview/qgraphicsview.cpp +++ b/src/gui/graphicsview/qgraphicsview.cpp @@ -855,6 +855,8 @@ void QGraphicsViewPrivate::_q_updateLaterSlot() const QList &dirtyItems = scene->d_func()->dirtyItems; for (int i = 0; i < dirtyItems.size(); ++i) { const QGraphicsItem *item = dirtyItems.at(i); + if (item->d_ptr->discardUpdateRequest()) + continue; QTransform x = item->sceneTransform() * viewTransform; updateRect(x.mapRect(item->boundingRect()).toAlignedRect() & vr); } -- cgit v0.12 From 9ed299a3edba92791e1c5af64b8fd9c9fe74c0ea Mon Sep 17 00:00:00 2001 From: Bjoern Erik Nilsen Date: Wed, 25 Mar 2009 12:38:35 +0100 Subject: Fixes: Optimize QGraphicsViewPrivate::itemUpdated. AutoTest: Still pass Details: Get rid of QTransform::inverted()/operator*= and do nothing if the item clips all its children and the update rect is outside the bounding rect. --- src/gui/graphicsview/qgraphicsview.cpp | 40 ++++++++++++++++------------------ 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp index 43263da..4db2257 100644 --- a/src/gui/graphicsview/qgraphicsview.cpp +++ b/src/gui/graphicsview/qgraphicsview.cpp @@ -801,38 +801,36 @@ void QGraphicsViewPrivate::itemUpdated(QGraphicsItem *item, const QRectF &rect) updateLater(); QRectF updateRect = rect; - if (item->isClipped()) { + if ((item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape) || item->d_ptr->children.isEmpty()) { + updateRect &= item->boundingRect(); + if (updateRect.isEmpty()) + return; + } + + QGraphicsItem *clipItem = item; + if (item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren) { // Minimize unnecessary redraw. - QGraphicsItem *p = item; - QTransform xform; - QGraphicsItem *lastTransformItem = 0; - while ((p = p->d_ptr->parent)) { - if (p->flags() & QGraphicsItem::ItemClipsChildrenToShape) { - if (!lastTransformItem) - xform = item->itemTransform(p); - else - xform *= lastTransformItem->itemTransform(p); - lastTransformItem = p; - updateRect &= xform.inverted().mapRect(p->boundingRect()); + QGraphicsItem *parent = item; + while ((parent = parent->d_ptr->parent)) { + if (parent->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape) { + // Map update rect to the current parent and itersect with its bounding rect. + updateRect = clipItem->itemTransform(parent).mapRect(updateRect) & parent->boundingRect(); if (updateRect.isEmpty()) return; + clipItem = parent; } - if (!(p->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren)) + if (!(parent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren)) break; } - - if (updateRect.isEmpty()) - return; } - // Map the rect to view coordinates. - QRect vr = viewport->rect(); - + // Map update rect from clipItem coordinates to view coordinates. + Q_ASSERT(clipItem); if (!item->d_ptr->hasBoundingRegionGranularity) - this->updateRect(mapToViewRect(item, updateRect) & vr); + this->updateRect(mapToViewRect(clipItem, updateRect) & viewport->rect()); else - updateRegion(mapToViewRegion(item, updateRect) & vr); + updateRegion(mapToViewRegion(clipItem, updateRect) & viewport->rect()); } void QGraphicsViewPrivate::updateLater() -- cgit v0.12 From a914eb155e085ba0efa5b95154bf7345d4be7cd7 Mon Sep 17 00:00:00 2001 From: Bjoern Erik Nilsen Date: Wed, 25 Mar 2009 13:41:10 +0100 Subject: Fixes: Minimize QVariant constr/destr in setPosHelper. RevBy: TrustMe --- src/gui/graphicsview/qgraphicsitem.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index a5d6021..396fdbd 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -2363,7 +2363,8 @@ void QGraphicsItemPrivate::setPosHelper(const QPointF &pos) return; // Notify the item that the position is changing. - QPointF newPos = q->itemChange(QGraphicsItem::ItemPositionChange, pos).toPointF(); + const QVariant newPosVariant(q->itemChange(QGraphicsItem::ItemPositionChange, pos)); + QPointF newPos = newPosVariant.toPointF(); if (newPos == this->pos) return; @@ -2378,7 +2379,7 @@ void QGraphicsItemPrivate::setPosHelper(const QPointF &pos) invalidateSceneTransformCache(); // Send post-notification. - q->itemChange(QGraphicsItem::ItemPositionHasChanged, newPos); + q->itemChange(QGraphicsItem::ItemPositionHasChanged, newPosVariant); inSetPosHelper = 0; } -- cgit v0.12 From 5564ef89f46fe96aa0b22b888a9a8ba053eea6c7 Mon Sep 17 00:00:00 2001 From: Bjoern Erik Nilsen Date: Thu, 26 Mar 2009 16:48:48 +0100 Subject: Fixes: Don't check the force boolean. Details: It's clipped away regardless. --- src/gui/graphicsview/qgraphicsitem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index 396fdbd..c691206 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -3635,7 +3635,7 @@ void QGraphicsItemPrivate::updateHelper(const QRectF &rect, bool force, bool may return; if (!scene || (scene && scene->d_func()->updateAll && scene->d_func()->hasSceneRect)) return; - if (!force && !maybeDirtyClipPath && discardUpdateRequest()) + if (!maybeDirtyClipPath && discardUpdateRequest()) return; if (scene && (visible || force)) { if (rect.isNull()) -- cgit v0.12 From 15098c5ec73db5de8ca724f744a1484f888ed271 Mon Sep 17 00:00:00 2001 From: Bjoern Erik Nilsen Date: Thu, 26 Mar 2009 17:05:59 +0100 Subject: Fixes: Do not update children if not required. AutoTest: Still pass --- src/gui/graphicsview/qgraphicsitem.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index c691206..b4f36de 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -1583,9 +1583,10 @@ void QGraphicsItemPrivate::setVisibleHelper(bool newVisible, bool explicitly, bo } // Update children with explicitly = false. + const bool updateChildren = update && !(flags & QGraphicsItem::ItemClipsChildrenToShape); foreach (QGraphicsItem *child, children) { if (!newVisible || !child->d_ptr->explicitlyHidden) - child->d_ptr->setVisibleHelper(newVisible, false); + child->d_ptr->setVisibleHelper(newVisible, false, updateChildren); } // Enable subfocus -- cgit v0.12 From d85835580463f88df6a71d27d2577739e5366f68 Mon Sep 17 00:00:00 2001 From: Bjoern Erik Nilsen Date: Thu, 26 Mar 2009 17:16:36 +0100 Subject: Fixes: Don't bother updating hidden items. AutoTest: Still pass --- src/gui/graphicsview/qgraphicsitem.cpp | 2 +- src/gui/graphicsview/qgraphicsscene.cpp | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index b4f36de..327b352 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -3652,7 +3652,7 @@ void QGraphicsItemPrivate::updateHelper(const QRectF &rect, bool force, bool may */ void QGraphicsItemPrivate::fullUpdateHelper(bool childrenOnly, bool