From 3ac9b6bdeb9f7522fa857fbc25a9da48e6d82186 Mon Sep 17 00:00:00 2001 From: Rohan McGovern Date: Tue, 9 Jun 2009 10:50:10 +1000 Subject: Fixed compile with MinGW 3.4. This compiler doesn't seem to follow the same rule as others for implicit conversions to/from wchar_t. Add the necessary casts, keeping in mind that sizeof(wchar_t) == 2 on Windows. --- src/gui/util/qdesktopservices_win.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/util/qdesktopservices_win.cpp b/src/gui/util/qdesktopservices_win.cpp index 8d2701c..9f8efb4 100644 --- a/src/gui/util/qdesktopservices_win.cpp +++ b/src/gui/util/qdesktopservices_win.cpp @@ -115,11 +115,11 @@ static bool launchWebBrowser(const QUrl &url) if (res == ERROR_SUCCESS) { returnValue = RegQueryValueEx(handle, L"Progid", 0, 0, reinterpret_cast(keyValue), &bufferSize); if (!returnValue) - keyName = QString::fromUtf16(keyValue); + keyName = QString::fromUtf16((const ushort*)keyValue); RegCloseKey(handle); } keyName += QLatin1String("\\Shell\\Open\\Command"); - res = RegOpenKeyExW(HKEY_CLASSES_ROOT, keyName.utf16(), 0, KEY_READ, &handle); + res = RegOpenKeyExW(HKEY_CLASSES_ROOT, (const wchar_t*)keyName.utf16(), 0, KEY_READ, &handle); if (res != ERROR_SUCCESS) return false; -- cgit v0.12 From a359abb4ccf5a2dc3bd1fac9836231677b3dc14f Mon Sep 17 00:00:00 2001 From: Rhys Weatherley Date: Tue, 9 Jun 2009 10:53:25 +1000 Subject: Protect EGL property names that only exist in some versions with #ifdefs Reviewed-by: trustme --- src/opengl/qegl.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/opengl/qegl.cpp b/src/opengl/qegl.cpp index f1ae4ed..290f77c 100644 --- a/src/opengl/qegl.cpp +++ b/src/opengl/qegl.cpp @@ -413,12 +413,18 @@ int QEglProperties::value(int name) const case EGL_RED_SIZE: return 0; case EGL_GREEN_SIZE: return 0; case EGL_BLUE_SIZE: return 0; - case EGL_LUMINANCE_SIZE: return 0; case EGL_ALPHA_SIZE: return 0; +#if defined(EGL_LUMINANCE_SIZE) + case EGL_LUMINANCE_SIZE: return 0; +#endif +#if defined(EGL_ALPHA_MASK_SIZE) case EGL_ALPHA_MASK_SIZE: return 0; +#endif case EGL_BIND_TO_TEXTURE_RGB: return EGL_DONT_CARE; case EGL_BIND_TO_TEXTURE_RGBA: return EGL_DONT_CARE; +#if defined(EGL_COLOR_BUFFER_TYPE) case EGL_COLOR_BUFFER_TYPE: return EGL_RGB_BUFFER; +#endif case EGL_CONFIG_CAVEAT: return EGL_DONT_CARE; case EGL_CONFIG_ID: return EGL_DONT_CARE; case EGL_DEPTH_SIZE: return 0; @@ -427,7 +433,9 @@ int QEglProperties::value(int name) const case EGL_NATIVE_VISUAL_TYPE: return EGL_DONT_CARE; case EGL_MAX_SWAP_INTERVAL: return EGL_DONT_CARE; case EGL_MIN_SWAP_INTERVAL: return EGL_DONT_CARE; +#if defined(EGL_RENDERABLE_TYPE) case EGL_RENDERABLE_TYPE: return EGL_OPENGL_ES_BIT; +#endif case EGL_SAMPLE_BUFFERS: return 0; case EGL_SAMPLES: return 0; case EGL_STENCIL_SIZE: return 0; -- cgit v0.12 From 1bbe23c5814dfda4cc6154c49e5bbf7c6ead7eba Mon Sep 17 00:00:00 2001 From: Rhys Weatherley Date: Tue, 9 Jun 2009 10:54:37 +1000 Subject: Make OpenGL/ES 1.1 work again for Qt/Embedded Reviewed-by: trustme --- src/opengl/qgl.cpp | 15 +++++++++++++++ src/opengl/qgl_p.h | 3 +-- src/opengl/qglframebufferobject.cpp | 2 ++ src/opengl/qglpixelbuffer.cpp | 5 +++-- 4 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp index 2e72851..37a9916 100644 --- a/src/opengl/qgl.cpp +++ b/src/opengl/qgl.cpp @@ -65,12 +65,19 @@ #include "qimage.h" #include "qgl_p.h" +#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL) #include "gl2paintengineex/qpaintengineex_opengl2_p.h" +#endif #ifndef QT_OPENGL_ES_2 #include #endif +#ifdef Q_WS_QWS +#include +#include +#endif + #include #include @@ -4428,7 +4435,11 @@ void QGLDrawable::swapBuffers() void QGLDrawable::makeCurrent() { previous_fbo = 0; +#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL) if (!pixmapData && !fbo) { +#else +#endif + if (!fbo) { QGLContext *ctx = context(); previous_fbo = ctx->d_ptr->current_fbo; ctx->d_ptr->current_fbo = 0; @@ -4561,8 +4572,10 @@ QColor QGLDrawable::backgroundColor() const { if (widget) return widget->palette().brush(widget->backgroundRole()).color(); +#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL) else if (pixmapData) return pixmapData->fillColor(); +#endif return QApplication::palette().brush(QPalette::Background).color(); } @@ -4590,8 +4603,10 @@ bool QGLDrawable::autoFillBackground() const { if (widget) return widget->autoFillBackground(); +#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL) else if (pixmapData) return pixmapData->needsFill(); +#endif else return false; } diff --git a/src/opengl/qgl_p.h b/src/opengl/qgl_p.h index b3523d4..4af8598 100644 --- a/src/opengl/qgl_p.h +++ b/src/opengl/qgl_p.h @@ -428,8 +428,7 @@ private: extern Q_OPENGL_EXPORT QGLShareRegister* qgl_share_reg(); #ifdef Q_WS_QWS -class QOpenGLPaintEngine; -extern QOpenGLPaintEngine* qt_qgl_paint_engine(); +extern QPaintEngine* qt_qgl_paint_engine(); extern EGLDisplay qt_qgl_egl_display(); #endif diff --git a/src/opengl/qglframebufferobject.cpp b/src/opengl/qglframebufferobject.cpp index 3e7ca0a..fb16107 100644 --- a/src/opengl/qglframebufferobject.cpp +++ b/src/opengl/qglframebufferobject.cpp @@ -43,7 +43,9 @@ #include #include +#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL) #include +#endif #ifndef QT_OPENGL_ES_2 #include diff --git a/src/opengl/qglpixelbuffer.cpp b/src/opengl/qglpixelbuffer.cpp index 483856a..0af97e3 100644 --- a/src/opengl/qglpixelbuffer.cpp +++ b/src/opengl/qglpixelbuffer.cpp @@ -76,12 +76,13 @@ \sa {opengl/pbuffers}{Pbuffers Example} */ -#include - #include #include #include +#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL) +#include +#endif #ifndef QT_OPENGL_ES_2 #include #endif -- cgit v0.12 From 6d4fe549e7a258913b19f52e29bcfb84cc8a97ad Mon Sep 17 00:00:00 2001 From: Rhys Weatherley Date: Tue, 9 Jun 2009 12:58:10 +1000 Subject: Fix build breakage from 1bbe23c5 - endif in the wrong place Reviewed-by: trustme --- src/opengl/qgl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp index 37a9916..146d088 100644 --- a/src/opengl/qgl.cpp +++ b/src/opengl/qgl.cpp @@ -4438,8 +4438,8 @@ void QGLDrawable::makeCurrent() #if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL) if (!pixmapData && !fbo) { #else -#endif if (!fbo) { +#endif QGLContext *ctx = context(); previous_fbo = ctx->d_ptr->current_fbo; ctx->d_ptr->current_fbo = 0; -- cgit v0.12 From cea87b08520888feff2f10d1bbf71bc8c2f1d780 Mon Sep 17 00:00:00 2001 From: Rhys Weatherley Date: Tue, 9 Jun 2009 13:20:51 +1000 Subject: Another breakage in 1bbe23c5 - move qpaintengineex_opengl2_p.h include up Moving qpaintengineex_opengl2_p.h down caused it to come after an include of , which causes problems on some platforms. Move it back up again. Reviewed-by: trustme --- src/opengl/qglpixelbuffer.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/opengl/qglpixelbuffer.cpp b/src/opengl/qglpixelbuffer.cpp index 0af97e3..9b7a506 100644 --- a/src/opengl/qglpixelbuffer.cpp +++ b/src/opengl/qglpixelbuffer.cpp @@ -76,13 +76,16 @@ \sa {opengl/pbuffers}{Pbuffers Example} */ -#include -#include -#include +#include #if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL) #include #endif + +#include +#include +#include + #ifndef QT_OPENGL_ES_2 #include #endif -- cgit v0.12 From ebcf875d90d940103e409de9127bb592d7336afe Mon Sep 17 00:00:00 2001 From: Martin Smith Date: Tue, 9 Jun 2009 09:10:53 +0200 Subject: qdoc: Inserted
between summary sections. Also added the left and right borders to the function headers in the detail sections. --- tools/qdoc3/htmlgenerator.cpp | 3 ++- tools/qdoc3/test/classic.css | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/qdoc3/htmlgenerator.cpp b/tools/qdoc3/htmlgenerator.cpp index 90d3b04..0c21534 100644 --- a/tools/qdoc3/htmlgenerator.cpp +++ b/tools/qdoc3/htmlgenerator.cpp @@ -1073,6 +1073,7 @@ void HtmlGenerator::generateClassLikeNode(const InnerNode *inner, if (!s->inherited.isEmpty()) needOtherSection = true; } else { + out() << "
\n"; out() << "\n"; @@ -2335,7 +2336,7 @@ void HtmlGenerator::generateSynopsis(const Node *node, QString HtmlGenerator::highlightedCode(const QString& markedCode, CodeMarker *marker, const Node *relative, - CodeMarker::SynopsisStyle style, + CodeMarker::SynopsisStyle , bool nameAlignment) { QString src = markedCode; diff --git a/tools/qdoc3/test/classic.css b/tools/qdoc3/test/classic.css index 3e2370d..85bb348 100644 --- a/tools/qdoc3/test/classic.css +++ b/tools/qdoc3/test/classic.css @@ -17,7 +17,7 @@ h3.fn,span.fn background-color: #e0eff6; border-width: 1px; border-style: solid; - border-color: #3388be #e0eff6 #e9f8ff #e0eff6; + border-color: #3388be #3388be #e9f8ff #3388be; font-weight: bold; padding: 6px 0px 6px 10px; } -- cgit v0.12 From b5c401b9aa3481886ad9e2d7816680c97839004e Mon Sep 17 00:00:00 2001 From: Andreas Aardal Hanssen Date: Mon, 25 May 2009 11:59:10 +0200 Subject: Add recursive drawing method to QGraphicsScene. For now it's opt-in, but the important thing is by effectively implementing Simple Canvas' approach to drawing, we're in theory (and in practise measured on the desktop) as fast as Simple Canvas when rendering. --- src/gui/graphicsview/qgraphicsscene.cpp | 82 +++++++++++++++++++++++++++++++++ src/gui/graphicsview/qgraphicsscene_p.h | 3 ++ src/gui/graphicsview/qgraphicsview.cpp | 34 ++++++++------ src/gui/graphicsview/qgraphicsview.h | 3 +- 4 files changed, 107 insertions(+), 15 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index 49c2329..362d66d 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -1870,6 +1870,11 @@ inline bool qt_closestLeaf(const QGraphicsItem *item1, const QGraphicsItem *item return z1 != z2 ? z1 > z2 : d1->siblingIndex > d2->siblingIndex; } +static inline bool qt_notclosestLeaf(const QGraphicsItem *item1, const QGraphicsItem *item2) +{ + return qt_closestLeaf(item2, item1); +} + /*! \internal @@ -5013,6 +5018,83 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte } } +void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter *painter, const QTransform &viewTransform, + const QRegion &exposedRegion, QWidget *widget) +{ + if (item && (!item->isVisible() || qFuzzyIsNull(item->opacity()))) + return; + + painter->save(); + + // Set transform + if (item) { + if (item->d_ptr->itemIsUntransformable()) { + painter->setWorldTransform(item->deviceTransform(viewTransform), false); + } else { + const QPointF &pos = item->d_ptr->pos; + bool posNull = pos.isNull(); + if (!posNull || item->d_ptr->hasTransform) { + if (item->d_ptr->hasTransform) { + QTransform x = item->transform(); + if (!posNull) + x *= QTransform::fromTranslate(pos.x(), pos.y()); + painter->setWorldTransform(x, true); + } else { + painter->setWorldTransform(QTransform::fromTranslate(pos.x(), pos.y()), true); + } + } + } + } + + // Setup recursive clipping. + if (item && (item->flags() & QGraphicsItem::ItemClipsChildrenToShape)) + painter->setClipPath(item->shape(), Qt::IntersectClip); + +#if 0 + const QList &children = item ? item->d_ptr->children : topLevelItems; +#else + // ### if we ensure all children are sorted by Z by default, we don't have + // to sort this list for each paint. + QList children = item ? item->d_ptr->children : topLevelItems; + qSort(children.begin(), children.end(), qt_notclosestLeaf); +#endif + + // Draw children behind + int i; + for (i = 0; i < children.size(); ++i) { + QGraphicsItem *child = children.at(i); + if (!(child->flags() & QGraphicsItem::ItemStacksBehindParent)) + break; + drawSubtreeRecursive(child, painter, viewTransform, exposedRegion, widget); + } + + // Draw item + if (item) { + QRect itemViewRect = painter->worldTransform().mapRect(item->boundingRect()).toRect().adjusted(-1, -1, 1, 1); + if (itemViewRect.intersects(exposedRegion.boundingRect())) { + QStyleOptionGraphicsItem option; + item->d_ptr->initStyleOption(&option, painter->worldTransform(), exposedRegion); + + bool clipsToShape = (item->flags() & QGraphicsItem::ItemClipsToShape); + if (clipsToShape) { + painter->save(); + painter->setClipPath(item->shape(), Qt::IntersectClip); + } + + drawItemHelper(item, painter, &option, widget, false); + + if (clipsToShape) + painter->restore(); + } + } + + // Draw children in front + for (; i < children.size(); ++i) + drawSubtreeRecursive(children.at(i), painter, viewTransform, exposedRegion, widget); + + painter->restore(); +} + /*! Paints the given \a items using the provided \a painter, after the background has been drawn, and before the foreground has been diff --git a/src/gui/graphicsview/qgraphicsscene_p.h b/src/gui/graphicsview/qgraphicsscene_p.h index 9ace725..369b0ef 100644 --- a/src/gui/graphicsview/qgraphicsscene_p.h +++ b/src/gui/graphicsview/qgraphicsscene_p.h @@ -253,6 +253,9 @@ public: const QStyleOptionGraphicsItem *option, QWidget *widget, bool painterStateProtection); + void drawSubtreeRecursive(QGraphicsItem *item, QPainter *painter, const QTransform &viewTransform, + const QRegion &exposedRegion, QWidget *widget); + QStyle *style; QFont font; void setFont_helper(const QFont &font); diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp index 10b837a..2459c49 100644 --- a/src/gui/graphicsview/qgraphicsview.cpp +++ b/src/gui/graphicsview/qgraphicsview.cpp @@ -3387,10 +3387,6 @@ void QGraphicsView::paintEvent(QPaintEvent *event) bool allItems = false; QList itemList = d->findItems(exposedRegion, &allItems); -#ifdef QGRAPHICSVIEW_DEBUG - int exposedTime = stopWatch.elapsed(); -#endif - if ((d->cacheMode & CacheBackground) #ifdef Q_WS_X11 && X11->use_xrender @@ -3436,16 +3432,26 @@ void QGraphicsView::paintEvent(QPaintEvent *event) int backgroundTime = stopWatch.elapsed() - exposedTime; #endif - if (!itemList.isEmpty()) { - // Generate the style options. - const int numItems = itemList.size(); - QGraphicsItem **itemArray = &itemList[0]; // Relies on QList internals, but is perfectly valid. - QStyleOptionGraphicsItem *styleOptionArray = d->allocStyleOptionsArray(numItems); - for (int i = 0; i < numItems; ++i) - itemArray[i]->d_ptr->initStyleOption(&styleOptionArray[i], viewTransform, exposedRegion, allItems); - // Draw the items. - drawItems(&painter, numItems, itemArray, styleOptionArray); - d->freeStyleOptionsArray(styleOptionArray); + const char *directEnv = getenv("QGRAPHICSVIEW_DIRECT"); + bool overrideDirectPaint = directEnv && atoi(directEnv) != 0; + if (overrideDirectPaint || (d->optimizationFlags & BypassDrawItems)) { + d->scene->d_func()->drawSubtreeRecursive(0, &painter, viewTransform, exposedRegion, viewport()); + } else { + // Find all exposed items + bool allItems = false; + QList itemList = d->findItems(exposedRegion, &allItems); + + if (!itemList.isEmpty()) { + // Generate the style options. + const int numItems = itemList.size(); + QGraphicsItem **itemArray = &itemList[0]; // Relies on QList internals, but is perfectly valid. + QStyleOptionGraphicsItem *styleOptionArray = d->allocStyleOptionsArray(numItems); + for (int i = 0; i < numItems; ++i) + itemArray[i]->d_ptr->initStyleOption(&styleOptionArray[i], viewTransform, exposedRegion, allItems); + // Draw the items. + drawItems(&painter, numItems, itemArray, styleOptionArray); + d->freeStyleOptionsArray(styleOptionArray); + } } #ifdef QGRAPHICSVIEW_DEBUG diff --git a/src/gui/graphicsview/qgraphicsview.h b/src/gui/graphicsview/qgraphicsview.h index c3ea6e5..7692e16 100644 --- a/src/gui/graphicsview/qgraphicsview.h +++ b/src/gui/graphicsview/qgraphicsview.h @@ -112,7 +112,8 @@ public: enum OptimizationFlag { DontClipPainter = 0x1, // obsolete DontSavePainterState = 0x2, - DontAdjustForAntialiasing = 0x4 + DontAdjustForAntialiasing = 0x4, + BypassDrawItems = 0x8 }; Q_DECLARE_FLAGS(OptimizationFlags, OptimizationFlag) -- cgit v0.12 From 1873203f3a3c64a2eb59bbc555eb8edf6b30315a Mon Sep 17 00:00:00 2001 From: Andreas Aardal Hanssen Date: Mon, 25 May 2009 16:41:31 +0200 Subject: Fix optimization flags and opacity. --- src/gui/graphicsview/qgraphicsscene.cpp | 44 +++++++++++++++++++++++---------- src/gui/graphicsview/qgraphicsscene_p.h | 3 ++- src/gui/graphicsview/qgraphicsview.cpp | 3 ++- 3 files changed, 35 insertions(+), 15 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index 362d66d..e360a07 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -5019,12 +5019,22 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte } void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter *painter, const QTransform &viewTransform, - const QRegion &exposedRegion, QWidget *widget) + const QRegion &exposedRegion, QWidget *widget, + QGraphicsView::OptimizationFlags optimizationFlags) { - if (item && (!item->isVisible() || qFuzzyIsNull(item->opacity()))) + if (item && (!item->isVisible())) return; - painter->save(); + bool hasOpacity = item && item->d_ptr->hasEffectiveOpacity; + bool childClip = (item && (item->flags() & QGraphicsItem::ItemClipsChildrenToShape)); + bool savePainter = !(optimizationFlags & QGraphicsView::DontSavePainterState); + + QTransform restoreTransform; + if (childClip || hasOpacity) { + painter->save(); + } else { + restoreTransform = painter->worldTransform(); + } // Set transform if (item) { @@ -5047,8 +5057,10 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * } // Setup recursive clipping. - if (item && (item->flags() & QGraphicsItem::ItemClipsChildrenToShape)) + if (childClip) painter->setClipPath(item->shape(), Qt::IntersectClip); + if (hasOpacity) + painter->setOpacity(item->effectiveOpacity()); #if 0 const QList &children = item ? item->d_ptr->children : topLevelItems; @@ -5065,34 +5077,40 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * QGraphicsItem *child = children.at(i); if (!(child->flags() & QGraphicsItem::ItemStacksBehindParent)) break; - drawSubtreeRecursive(child, painter, viewTransform, exposedRegion, widget); + drawSubtreeRecursive(child, painter, viewTransform, exposedRegion, widget, optimizationFlags); } // Draw item - if (item) { - QRect itemViewRect = painter->worldTransform().mapRect(item->boundingRect()).toRect().adjusted(-1, -1, 1, 1); + if (item && !item->d_ptr->isFullyTransparent()) { + QRectF brect = item->boundingRect(); + _q_adjustRect(&brect); + QRect itemViewRect = painter->worldTransform().mapRect(brect).toRect().adjusted(-1, -1, 1, 1); if (itemViewRect.intersects(exposedRegion.boundingRect())) { QStyleOptionGraphicsItem option; item->d_ptr->initStyleOption(&option, painter->worldTransform(), exposedRegion); bool clipsToShape = (item->flags() & QGraphicsItem::ItemClipsToShape); - if (clipsToShape) { + if (savePainter || clipsToShape) painter->save(); + if (clipsToShape) painter->setClipPath(item->shape(), Qt::IntersectClip); - } drawItemHelper(item, painter, &option, widget, false); - - if (clipsToShape) + + if (savePainter || clipsToShape) painter->restore(); } } // Draw children in front for (; i < children.size(); ++i) - drawSubtreeRecursive(children.at(i), painter, viewTransform, exposedRegion, widget); + drawSubtreeRecursive(children.at(i), painter, viewTransform, exposedRegion, widget, optimizationFlags); - painter->restore(); + if (childClip || hasOpacity) { + painter->restore(); + } else { + painter->setWorldTransform(restoreTransform, /* combine = */ false); + } } /*! diff --git a/src/gui/graphicsview/qgraphicsscene_p.h b/src/gui/graphicsview/qgraphicsscene_p.h index 369b0ef..0ac1765 100644 --- a/src/gui/graphicsview/qgraphicsscene_p.h +++ b/src/gui/graphicsview/qgraphicsscene_p.h @@ -57,6 +57,7 @@ #if !defined(QT_NO_GRAPHICSVIEW) || (QT_EDITION & QT_MODULE_GRAPHICSVIEW) != QT_MODULE_GRAPHICSVIEW +#include "qgraphicsview.h" #include "qgraphicsscene_bsp_p.h" #include "qgraphicsitem_p.h" @@ -254,7 +255,7 @@ public: bool painterStateProtection); void drawSubtreeRecursive(QGraphicsItem *item, QPainter *painter, const QTransform &viewTransform, - const QRegion &exposedRegion, QWidget *widget); + const QRegion &exposedRegion, QWidget *widget, QGraphicsView::OptimizationFlags optimizationFlags); QStyle *style; QFont font; diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp index 2459c49..40c84db 100644 --- a/src/gui/graphicsview/qgraphicsview.cpp +++ b/src/gui/graphicsview/qgraphicsview.cpp @@ -3435,7 +3435,8 @@ void QGraphicsView::paintEvent(QPaintEvent *event) const char *directEnv = getenv("QGRAPHICSVIEW_DIRECT"); bool overrideDirectPaint = directEnv && atoi(directEnv) != 0; if (overrideDirectPaint || (d->optimizationFlags & BypassDrawItems)) { - d->scene->d_func()->drawSubtreeRecursive(0, &painter, viewTransform, exposedRegion, viewport()); + d->scene->d_func()->drawSubtreeRecursive(0, &painter, viewTransform, exposedRegion, + viewport(), d->optimizationFlags); } else { // Find all exposed items bool allItems = false; -- cgit v0.12 From 6cbc582c9699498e7f1762121bb2cff04d2596ce Mon Sep 17 00:00:00 2001 From: Andreas Aardal Hanssen Date: Mon, 25 May 2009 17:15:03 +0200 Subject: Minor optimizations. --- src/gui/graphicsview/qgraphicsscene.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index e360a07..45108ca 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -5022,15 +5022,14 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * const QRegion &exposedRegion, QWidget *widget, QGraphicsView::OptimizationFlags optimizationFlags) { - if (item && (!item->isVisible())) + if (item && !item->d_ptr->visible) return; - bool hasOpacity = item && item->d_ptr->hasEffectiveOpacity; - bool childClip = (item && (item->flags() & QGraphicsItem::ItemClipsChildrenToShape)); + bool childClip = (item && (item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape)); bool savePainter = !(optimizationFlags & QGraphicsView::DontSavePainterState); QTransform restoreTransform; - if (childClip || hasOpacity) { + if (childClip) { painter->save(); } else { restoreTransform = painter->worldTransform(); @@ -5059,7 +5058,7 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * // Setup recursive clipping. if (childClip) painter->setClipPath(item->shape(), Qt::IntersectClip); - if (hasOpacity) + if (item) painter->setOpacity(item->effectiveOpacity()); #if 0 @@ -5075,7 +5074,7 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * int i; for (i = 0; i < children.size(); ++i) { QGraphicsItem *child = children.at(i); - if (!(child->flags() & QGraphicsItem::ItemStacksBehindParent)) + if (!(child->d_ptr->flags & QGraphicsItem::ItemStacksBehindParent)) break; drawSubtreeRecursive(child, painter, viewTransform, exposedRegion, widget, optimizationFlags); } @@ -5089,7 +5088,7 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * QStyleOptionGraphicsItem option; item->d_ptr->initStyleOption(&option, painter->worldTransform(), exposedRegion); - bool clipsToShape = (item->flags() & QGraphicsItem::ItemClipsToShape); + bool clipsToShape = (item->d_ptr->flags & QGraphicsItem::ItemClipsToShape); if (savePainter || clipsToShape) painter->save(); if (clipsToShape) @@ -5106,7 +5105,7 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * for (; i < children.size(); ++i) drawSubtreeRecursive(children.at(i), painter, viewTransform, exposedRegion, widget, optimizationFlags); - if (childClip || hasOpacity) { + if (childClip) { painter->restore(); } else { painter->setWorldTransform(restoreTransform, /* combine = */ false); -- cgit v0.12 From 6f1cca3661b794f170ed00fdc84e8ad31789aa9f Mon Sep 17 00:00:00 2001 From: Andreas Aardal Hanssen Date: Tue, 26 May 2009 09:07:44 +0200 Subject: Further optimizations, from the simple canvas rendering logics. --- src/gui/graphicsview/qgraphicsscene.cpp | 115 +++++++++++++++++--------------- src/gui/graphicsview/qgraphicsscene_p.h | 3 +- src/gui/graphicsview/qgraphicsview.cpp | 2 +- 3 files changed, 63 insertions(+), 57 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index 45108ca..7eb49e9 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -5018,27 +5018,20 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte } } -void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter *painter, const QTransform &viewTransform, +void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter *painter, const QTransform &parentTransform, + const QTransform &viewTransform, const QRegion &exposedRegion, QWidget *widget, QGraphicsView::OptimizationFlags optimizationFlags) { - if (item && !item->d_ptr->visible) + if (item && item->d_ptr->isInvisible()) return; - bool childClip = (item && (item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape)); - bool savePainter = !(optimizationFlags & QGraphicsView::DontSavePainterState); - - QTransform restoreTransform; - if (childClip) { - painter->save(); - } else { - restoreTransform = painter->worldTransform(); - } - - // Set transform + // Calculate the full transform for this item. + QTransform transform; + QRect viewBoundingRect; if (item) { if (item->d_ptr->itemIsUntransformable()) { - painter->setWorldTransform(item->deviceTransform(viewTransform), false); + transform = item->deviceTransform(viewTransform); } else { const QPointF &pos = item->d_ptr->pos; bool posNull = pos.isNull(); @@ -5047,69 +5040,81 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * QTransform x = item->transform(); if (!posNull) x *= QTransform::fromTranslate(pos.x(), pos.y()); - painter->setWorldTransform(x, true); + transform = x * parentTransform; } else { - painter->setWorldTransform(QTransform::fromTranslate(pos.x(), pos.y()), true); + transform = QTransform::fromTranslate(pos.x(), pos.y()) * parentTransform; } + } else { + transform = parentTransform; } } + QRectF brect = item->boundingRect(); + _q_adjustRect(&brect); + viewBoundingRect = transform.mapRect(brect).toRect().adjusted(-1, -1, 1, 1) & exposedRegion.boundingRect(); + } else { + transform = parentTransform; } - // Setup recursive clipping. - if (childClip) - painter->setClipPath(item->shape(), Qt::IntersectClip); - if (item) - painter->setOpacity(item->effectiveOpacity()); - -#if 0 - const QList &children = item ? item->d_ptr->children : topLevelItems; -#else - // ### if we ensure all children are sorted by Z by default, we don't have - // to sort this list for each paint. + // Find and sort children. QList children = item ? item->d_ptr->children : topLevelItems; qSort(children.begin(), children.end(), qt_notclosestLeaf); -#endif + + bool childClip = (item && (item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape)); + bool dontDrawItem = !item || viewBoundingRect.isEmpty(); + bool dontDrawChildren = item && dontDrawItem && childClip; + childClip &= !dontDrawChildren & !children.isEmpty(); + + // Clip children. + if (childClip) { + painter->save(); + painter->setWorldTransform(transform); + painter->setClipPath(item->shape(), Qt::IntersectClip); + } // Draw children behind int i; - for (i = 0; i < children.size(); ++i) { - QGraphicsItem *child = children.at(i); - if (!(child->d_ptr->flags & QGraphicsItem::ItemStacksBehindParent)) - break; - drawSubtreeRecursive(child, painter, viewTransform, exposedRegion, widget, optimizationFlags); + if (!dontDrawChildren) { + for (i = 0; i < children.size(); ++i) { + QGraphicsItem *child = children.at(i); + if (!(child->d_ptr->flags & QGraphicsItem::ItemStacksBehindParent)) + break; + drawSubtreeRecursive(child, painter, transform, viewTransform, + exposedRegion, widget, optimizationFlags); + } } // Draw item - if (item && !item->d_ptr->isFullyTransparent()) { - QRectF brect = item->boundingRect(); - _q_adjustRect(&brect); - QRect itemViewRect = painter->worldTransform().mapRect(brect).toRect().adjusted(-1, -1, 1, 1); - if (itemViewRect.intersects(exposedRegion.boundingRect())) { - QStyleOptionGraphicsItem option; - item->d_ptr->initStyleOption(&option, painter->worldTransform(), exposedRegion); + if (!dontDrawItem) { + QStyleOptionGraphicsItem option; + item->d_ptr->initStyleOption(&option, transform, exposedRegion); - bool clipsToShape = (item->d_ptr->flags & QGraphicsItem::ItemClipsToShape); - if (savePainter || clipsToShape) - painter->save(); - if (clipsToShape) - painter->setClipPath(item->shape(), Qt::IntersectClip); + bool clipsToShape = (item->d_ptr->flags & QGraphicsItem::ItemClipsToShape); + bool savePainter = clipsToShape || !(optimizationFlags & QGraphicsView::DontSavePainterState); + if (savePainter) + painter->save(); + if (!childClip) + painter->setWorldTransform(transform); + if (clipsToShape) + painter->setClipPath(item->shape(), Qt::IntersectClip); + painter->setOpacity(item->effectiveOpacity()); - drawItemHelper(item, painter, &option, widget, false); + drawItemHelper(item, painter, &option, widget, false); - if (savePainter || clipsToShape) - painter->restore(); - } + if (savePainter) + painter->restore(); } // Draw children in front - for (; i < children.size(); ++i) - drawSubtreeRecursive(children.at(i), painter, viewTransform, exposedRegion, widget, optimizationFlags); + if (!dontDrawChildren) { + for (; i < children.size(); ++i) { + drawSubtreeRecursive(children.at(i), painter, transform, viewTransform, + exposedRegion, widget, optimizationFlags); + } + } - if (childClip) { + // Restore child clip + if (childClip) painter->restore(); - } else { - painter->setWorldTransform(restoreTransform, /* combine = */ false); - } } /*! diff --git a/src/gui/graphicsview/qgraphicsscene_p.h b/src/gui/graphicsview/qgraphicsscene_p.h index 0ac1765..bb99908 100644 --- a/src/gui/graphicsview/qgraphicsscene_p.h +++ b/src/gui/graphicsview/qgraphicsscene_p.h @@ -254,7 +254,8 @@ public: const QStyleOptionGraphicsItem *option, QWidget *widget, bool painterStateProtection); - void drawSubtreeRecursive(QGraphicsItem *item, QPainter *painter, const QTransform &viewTransform, + void drawSubtreeRecursive(QGraphicsItem *item, QPainter *painter, const QTransform &parentTransform, + const QTransform &viewTransform, const QRegion &exposedRegion, QWidget *widget, QGraphicsView::OptimizationFlags optimizationFlags); QStyle *style; diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp index 40c84db..1994675 100644 --- a/src/gui/graphicsview/qgraphicsview.cpp +++ b/src/gui/graphicsview/qgraphicsview.cpp @@ -3435,7 +3435,7 @@ void QGraphicsView::paintEvent(QPaintEvent *event) const char *directEnv = getenv("QGRAPHICSVIEW_DIRECT"); bool overrideDirectPaint = directEnv && atoi(directEnv) != 0; if (overrideDirectPaint || (d->optimizationFlags & BypassDrawItems)) { - d->scene->d_func()->drawSubtreeRecursive(0, &painter, viewTransform, exposedRegion, + d->scene->d_func()->drawSubtreeRecursive(0, &painter, viewTransform, viewTransform, exposedRegion, viewport(), d->optimizationFlags); } else { // Find all exposed items -- cgit v0.12 From e7c7e4f57530d7b3571bf11dbe555c52f6dc3f34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Nilsen?= Date: Tue, 26 May 2009 20:23:54 +0200 Subject: Cache QGraphicsItem::childrenBoundingRect. We'll need this later when making a smarter update mechanism. --- src/gui/graphicsview/qgraphicsitem.cpp | 15 +++++++++++++++ src/gui/graphicsview/qgraphicsitem_p.h | 5 ++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index b9e462b..e09d3f0 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -925,6 +925,11 @@ void QGraphicsItemPrivate::setParentItemHelper(QGraphicsItem *newParent, bool de */ void QGraphicsItemPrivate::childrenBoundingRectHelper(QTransform *x, QRectF *rect) { + if (!dirtyChildrenBoundingRect) { + *rect |= x->mapRect(childrenBoundingRect); + return; + } + for (int i = 0; i < children.size(); ++i) { QGraphicsItem *child = children.at(i); QGraphicsItemPrivate *childd = child->d_ptr; @@ -948,6 +953,9 @@ void QGraphicsItemPrivate::childrenBoundingRectHelper(QTransform *x, QRectF *rec childd->childrenBoundingRectHelper(x, rect); } } + + childrenBoundingRect = *rect; + dirtyChildrenBoundingRect = 0; } void QGraphicsItemPrivate::initStyleOption(QStyleOptionGraphicsItem *option, const QTransform &worldTransform, @@ -3567,6 +3575,9 @@ void QGraphicsItem::setZValue(qreal z) */ QRectF QGraphicsItem::childrenBoundingRect() const { + if (!d_ptr->dirtyChildrenBoundingRect) + return d_ptr->childrenBoundingRect; + QRectF childRect; QTransform x; d_ptr->childrenBoundingRectHelper(&x, &childRect); @@ -6400,6 +6411,10 @@ void QGraphicsItem::prepareGeometryChange() scenePrivate->removeFromIndex(this); } + QGraphicsItem *parent = this; + while (parent = parent->d_ptr->parent) + parent->d_ptr->dirtyChildrenBoundingRect = 1; + if (d_ptr->inSetPosHelper) return; diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index bd81fe5..200d177 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -160,6 +160,7 @@ public: hasDecomposedTransform(0), dirtyTransform(0), dirtyTransformComponents(0), + dirtyChildrenBoundingRect(1), globalStackingOrder(-1), sceneTransformIndex(-1), q_ptr(0) @@ -308,6 +309,7 @@ public: } QPainterPath cachedClipPath; + QRectF childrenBoundingRect; QPointF pos; qreal z; QGraphicsScene *scene; @@ -350,7 +352,8 @@ public: quint32 hasDecomposedTransform : 1; quint32 dirtyTransform : 1; quint32 dirtyTransformComponents : 1; - quint32 padding : 18; // feel free to use + quint32 dirtyChildrenBoundingRect : 1; + quint32 padding : 17; // feel free to use // Optional stacking order int globalStackingOrder; -- cgit v0.12 From 63a3c0ad549b57d0896f267383cf671d6212a70e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Nilsen?= Date: Wed, 27 May 2009 21:31:44 +0200 Subject: Massive re-factoring of Graphics View's update mechanism. This is work-in-progress, so don't expect everything to work perfectly. Most of the auto-test pass and examples and demos seem to run fine. Unfortunately I'm too tired to write about the actual update mehanism now, but it's faster than the old approach (if that helps:)). There's more to optimize, but I'll come back to that later. I need some sleep now :) To be continued. --- src/gui/graphicsview/qgraphicsitem.cpp | 156 ++++++----------- src/gui/graphicsview/qgraphicsitem_p.h | 22 ++- src/gui/graphicsview/qgraphicsscene.cpp | 212 ++++++++++++----------- src/gui/graphicsview/qgraphicsscene.h | 4 +- src/gui/graphicsview/qgraphicsscene_p.h | 30 +++- src/gui/graphicsview/qgraphicsview.cpp | 194 ++++----------------- src/gui/graphicsview/qgraphicsview.h | 1 - src/gui/graphicsview/qgraphicsview_p.h | 9 +- tests/auto/qgraphicsscene/tst_qgraphicsscene.cpp | 5 +- 9 files changed, 253 insertions(+), 380 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index e09d3f0..ec6b35b 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -863,8 +863,11 @@ void QGraphicsItemPrivate::setParentItemHelper(QGraphicsItem *newParent, bool de parent->d_ptr->addChild(q); parent->itemChange(QGraphicsItem::ItemChildAddedChange, thisPointerVariant); - if (!implicitUpdate) - updateHelper(QRectF(), false, true); + if (!implicitUpdate && scene) { + scene->d_func()->markDirty(q_ptr, QRect(), + /*invalidateChildren=*/false, + /*maybeDirtyClipPath=*/true); + } // Inherit ancestor flags from the new parent. updateAncestorFlag(QGraphicsItem::GraphicsItemFlag(-1)); @@ -895,7 +898,11 @@ void QGraphicsItemPrivate::setParentItemHelper(QGraphicsItem *newParent, bool de setEnabledHelper(true, /* explicit = */ false); // If the item is being deleted, the whole scene will be updated. - updateHelper(QRectF(), false, true); + if (scene) { + scene->d_func()->markDirty(q_ptr, QRect(), + /*invalidateChildren=*/false, + /*maybeDirtyClipPath=*/true); + } } } @@ -1358,7 +1365,7 @@ void QGraphicsItem::setFlags(GraphicsItemFlags flags) const quint32 geomChangeFlagsMask = (ItemClipsChildrenToShape | ItemClipsToShape | ItemIgnoresTransformations); bool fullUpdate = (quint32(flags) & geomChangeFlagsMask) != (d_ptr->flags & geomChangeFlagsMask); if (fullUpdate) - d_ptr->fullUpdateHelper(false, true); + d_ptr->paintedViewBoundingRectsNeedRepaint = 1; // Keep the old flags to compare the diff. GraphicsItemFlags oldFlags = this->flags(); @@ -1398,8 +1405,11 @@ void QGraphicsItem::setFlags(GraphicsItemFlags flags) d_ptr->updateAncestorFlag(ItemIgnoresTransformations); } - // ### Why updateHelper? - d_ptr->updateHelper(QRectF(), false, true); + if (d_ptr->scene) { + d_ptr->scene->d_func()->markDirty(this, QRectF(), + /*invalidateChildren=*/true, + /*maybeDirtyClipPath*/true); + } // Notify change. itemChange(ItemFlagsHaveChanged, quint32(flags)); @@ -1665,7 +1675,12 @@ void QGraphicsItemPrivate::setVisibleHelper(bool newVisible, bool explicitly, bo QGraphicsItemCache *c = (QGraphicsItemCache *)qVariantValue(extra(ExtraCacheData)); if (c) c->purge(); - updateHelper(QRectF(), /* force = */ true); + if (scene) { + scene->d_func()->markDirty(q_ptr, QRectF(), + /*invalidateChildren=*/false, + /*maybeDirtyClipPath=*/false, + /*force=*/true); + } } // Certain properties are dropped as an item becomes invisible. @@ -1828,8 +1843,8 @@ void QGraphicsItemPrivate::setEnabledHelper(bool newEnabled, bool explicitly, bo enabled = newEnabledVariant.toBool(); // Schedule redraw. - if (update) - updateHelper(); + if (update && scene) + scene->d_func()->markDirty(q_ptr); foreach (QGraphicsItem *child, children) { if (!newEnabled || !child->d_ptr->explicitlyDisabled) @@ -1930,9 +1945,8 @@ void QGraphicsItem::setSelected(bool selected) return; d_ptr->selected = newSelected; - d_ptr->updateHelper(); - if (d_ptr->scene) { + d_ptr->scene->d_func()->markDirty(this); QGraphicsScenePrivate *sceneD = d_ptr->scene->d_func(); if (selected) { sceneD->selectedItems << this; @@ -2051,7 +2065,12 @@ void QGraphicsItem::setOpacity(qreal opacity) itemChange(ItemOpacityHasChanged, newOpacity); // Update. - d_ptr->fullUpdateHelper(/*childrenOnly=*/false, /*maybeDirtyClipPath=*/false, /*ignoreOpacity=*/true); + if (d_ptr->scene) + d_ptr->scene->d_func()->markDirty(this, QRectF(), + /*invalidateChildren=*/true, + /*maybeDirtyClipPath=*/false, + /*force=*/false, + /*ignoreOpacity=*/true); } /*! @@ -2501,10 +2520,8 @@ void QGraphicsItemPrivate::setPosHelper(const QPointF &pos) // Update and repositition. inSetPosHelper = 1; updateCachedClipPathFromSetPosHelper(newPos); - if (scene) { - fullUpdateHelper(true); + if (scene) q->prepareGeometryChange(); - } this->pos = newPos; invalidateSceneTransformCache(); @@ -3305,7 +3322,6 @@ void QGraphicsItem::setMatrix(const QMatrix &matrix, bool combine) return; // Update and set the new transformation. - d_ptr->fullUpdateHelper(true, true); prepareGeometryChange(); d_ptr->hasTransform = !newTransform.isIdentity(); d_ptr->setExtra(QGraphicsItemPrivate::ExtraTransform, newTransform); @@ -3358,7 +3374,6 @@ void QGraphicsItem::setTransform(const QTransform &matrix, bool combine) return; // Update and set the new transformation. - d_ptr->fullUpdateHelper(true, true); prepareGeometryChange(); d_ptr->hasTransform = !newTransform.isIdentity(); d_ptr->setExtra(QGraphicsItemPrivate::ExtraTransform, newTransform); @@ -3545,9 +3560,9 @@ void QGraphicsItem::setZValue(qreal z) if (newZ == d_ptr->z) return; d_ptr->z = newZ; - d_ptr->fullUpdateHelper(); if (d_ptr->scene) { + d_ptr->scene->d_func()->markDirty(this, QRectF(), /*invalidateChildren=*/true); // Invalidate any sort caching; arrival of a new item means we need to // resort. d_ptr->scene->d_func()->invalidateSortCache(); @@ -4208,84 +4223,13 @@ bool QGraphicsItemPrivate::discardUpdateRequest(bool ignoreClipping, bool ignore // 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. return (!visible && !ignoreVisibleBit) - || (dirty && !ignoreDirtyBit) + || (!ignoreDirtyBit && (dirty || hasDirtyAncestor())) || !scene || (scene->d_func()->updateAll && scene->d_func()->hasSceneRect) || (!ignoreClipping && (childrenClippedToShape() && isClippedAway())) || (!ignoreOpacity && childrenCombineOpacity() && isFullyTransparent()); } -/*! - \internal - - Asks the scene to mark this item's scene rect as dirty, requesting a - redraw. This does not invalidate any cache. - - The \a force argument is for the update call in setVisible(), which is the - 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, 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. - if (discardUpdateRequest(/*ignoreClipping=*/maybeDirtyClipPath, /*ignoreVisibleBit=*/force)) - return; - - if (rect.isNull()) - dirty = 1; - scene->itemUpdated(q_ptr, rect); -} - -/*! - \internal - - Propagates updates to \a item and all its children. -*/ -void QGraphicsItemPrivate::fullUpdateHelper(bool childrenOnly, bool maybeDirtyClipPath, bool ignoreOpacity) -{ - if (discardUpdateRequest(/*ignoreClipping=*/maybeDirtyClipPath, /*ignoreVisibleBit=*/false, - /*ignoreDirtyBit=*/true, ignoreOpacity)) { - return; - } - - if (!childrenOnly && !dirty) { - // Effectively the same as updateHelper(QRectF(), false, maybeDirtyClipPath). - dirty = 1; - scene->itemUpdated(q_ptr, QRectF()); - } - - if (dirtyChildren || childrenClippedToShape()) { - // Unnecessary to update children as well. - return; - } - - if (ancestorFlags & AncestorClipsChildren) { - Q_Q(QGraphicsItem); - // Check if we can avoid updating all children. - QGraphicsItem *p = parent; - QRectF br = q->boundingRect(); - while (p) { - if (p->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape) { - bool ok; - QTransform x = q->itemTransform(p, &ok); - if (!ok) - break; - if (x.mapRect(br).contains(p->boundingRect())) - return; - } - p = p->d_ptr->parent; - if (!p || !(p->d_ptr->ancestorFlags & AncestorClipsChildren)) - break; - // ### check one level only - break; - } - } - foreach (QGraphicsItem *child, children) - child->d_ptr->fullUpdateHelper(false, maybeDirtyClipPath); - dirtyChildren = 1; -} - static inline bool allChildrenCombineOpacityHelper(QGraphicsItem *parent) { Q_ASSERT(parent); @@ -4590,14 +4534,10 @@ void QGraphicsItem::update(const QRectF &rect) // Only invalidate cache; item is already dirty. if (d_ptr->dirty) return; - } else if (d_ptr->discardUpdateRequest()) { - return; } - // Effectively the same as updateHelper(rect); - if (rect.isNull()) - d_ptr->dirty = 1; - d_ptr->scene->itemUpdated(this, rect); + if (d_ptr->scene) + d_ptr->scene->d_func()->markDirty(this); } /*! @@ -4695,7 +4635,7 @@ void QGraphicsItem::scroll(qreal dx, qreal dy, const QRectF &rect) exposed -= r.translated(dx, dy); foreach (QRect rect, exposed.rects()) update(rect); - d_ptr->updateHelper(); + d->scene->d_func()->markDirty(this); } else { update(rect); } @@ -5911,7 +5851,8 @@ void QGraphicsItem::focusOutEvent(QFocusEvent *event) void QGraphicsItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event) { Q_UNUSED(event); - d_ptr->updateHelper(); + if (d_ptr->scene) + d_ptr->scene->d_func()->markDirty(this); } /*! @@ -5939,7 +5880,8 @@ void QGraphicsItem::hoverMoveEvent(QGraphicsSceneHoverEvent *event) void QGraphicsItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event) { Q_UNUSED(event); - d_ptr->updateHelper(); + if (d_ptr->scene) + d_ptr->scene->d_func()->markDirty(this); } /*! @@ -6367,9 +6309,10 @@ void QGraphicsItem::addToIndex() // ### add to child index only if applicable return; } - if (d_ptr->scene) + if (d_ptr->scene) { d_ptr->scene->d_func()->addToIndex(this); - d_ptr->updateHelper(); + d_ptr->scene->d_func()->markDirty(this); + } } /*! @@ -6385,9 +6328,10 @@ void QGraphicsItem::removeFromIndex() // ### remove from child index only if applicable return; } - d_ptr->updateHelper(); - if (d_ptr->scene) + if (d_ptr->scene) { + d_ptr->scene->d_func()->markDirty(this); d_ptr->scene->d_func()->removeFromIndex(this); + } } /*! @@ -6406,7 +6350,10 @@ void QGraphicsItem::removeFromIndex() void QGraphicsItem::prepareGeometryChange() { if (d_ptr->scene) { - d_ptr->updateHelper(QRectF(), false, /*maybeDirtyClipPath=*/!d_ptr->inSetPosHelper); + d_ptr->paintedViewBoundingRectsNeedRepaint = 1; + d_ptr->scene->d_func()->markDirty(this, QRectF(), + /*invalidateChildren=*/true, + /*maybeDirtyClipPath=*/!d_ptr->inSetPosHelper); QGraphicsScenePrivate *scenePrivate = d_ptr->scene->d_func(); scenePrivate->removeFromIndex(this); } @@ -8075,7 +8022,6 @@ void QGraphicsPixmapItem::setTransformationMode(Qt::TransformationMode mode) { Q_D(QGraphicsPixmapItem); if (mode != d->transformationMode) { - d_ptr->updateHelper(); d->transformationMode = mode; update(); } diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index 200d177..1d4b37a 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -161,6 +161,8 @@ public: dirtyTransform(0), dirtyTransformComponents(0), dirtyChildrenBoundingRect(1), + inDirtyList(0), + paintedViewBoundingRectsNeedRepaint(0), globalStackingOrder(-1), sceneTransformIndex(-1), q_ptr(0) @@ -186,8 +188,6 @@ public: void setEnabledHelper(bool newEnabled, bool explicitly, bool update = true); bool discardUpdateRequest(bool ignoreClipping = false, bool ignoreVisibleBit = false, bool ignoreDirtyBit = false, bool ignoreOpacity = false) const; - void updateHelper(const QRectF &rect = QRectF(), bool force = false, bool maybeDirtyClipPath = false); - void fullUpdateHelper(bool childrenOnly = false, bool maybeDirtyClipPath = false, bool ignoreOpacity = false); void updateEffectiveOpacity(); void resolveEffectiveOpacity(qreal effectiveParentOpacity); void resolveDepth(int parentDepth); @@ -308,8 +308,22 @@ public: || (childrenCombineOpacity() && isFullyTransparent()); } + inline bool hasDirtyAncestor() const + { + QGraphicsItem *p = parent; + while (p) { + if (p->d_ptr->dirtyChildren || (p->d_ptr->dirty && p->d_ptr->childrenClippedToShape())) + return true; + p = p->d_ptr->parent; + } + return false; + } + + QPainterPath cachedClipPath; QRectF childrenBoundingRect; + QRectF needsRepaint; + QMap paintedViewBoundingRects; QPointF pos; qreal z; QGraphicsScene *scene; @@ -353,7 +367,9 @@ public: quint32 dirtyTransform : 1; quint32 dirtyTransformComponents : 1; quint32 dirtyChildrenBoundingRect : 1; - quint32 padding : 17; // feel free to use + quint32 inDirtyList : 1; + quint32 paintedViewBoundingRectsNeedRepaint : 1; + quint32 padding : 15; // feel free to use // Optional stacking order int globalStackingOrder; diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index 7eb49e9..d004ed2 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -334,7 +334,6 @@ QGraphicsScenePrivate::QGraphicsScenePrivate() updateAll(false), calledEmitUpdated(false), selectionChanging(0), - dirtyItemResetPending(false), regenerateIndex(true), purgePending(false), indexTimerId(0), @@ -678,31 +677,81 @@ void QGraphicsScenePrivate::_q_polishItems() unpolishedItems.clear(); } -/*! - \internal -*/ -void QGraphicsScenePrivate::_q_resetDirtyItems() +void QGraphicsScenePrivate::_q_processDirtyItems() { + Q_Q(QGraphicsScene); + if (dirtyItems.isEmpty()) + return; + + if (updateAll) { + for (int i = 0; i < dirtyItems.size(); ++i) + resetDirtyItem(dirtyItems.at(i)); + dirtyItems.clear(); + return; + } + + const bool useCompatUpdate = views.isEmpty() || (connectedSignals & changedSignalMask); for (int i = 0; i < dirtyItems.size(); ++i) { QGraphicsItem *item = dirtyItems.at(i); - item->d_ptr->dirty = 0; - item->d_ptr->dirtyChildren = 0; + if (useCompatUpdate && !item->d_ptr->itemIsUntransformable() + && qFuzzyIsNull(item->boundingRegionGranularity())) { + // This block of code is kept for compatibility. Since 4.5, by default + // QGraphicsView does not connect the signal and we use the below + // method of delivering updates. + q->update(item->sceneBoundingRect()); + resetDirtyItem(item); + continue; + } + + QRectF dirtyRect; + bool uninitializedDirtyRect = true; + + for (int j = 0; j < views.size(); ++j) { + QGraphicsView *view = views.at(j); + QGraphicsViewPrivate *viewPrivate = view->d_func(); + if (viewPrivate->fullUpdatePending) + continue; + switch (viewPrivate->viewportUpdateMode) { + case QGraphicsView::NoViewportUpdate: + continue; + case QGraphicsView::FullViewportUpdate: + view->viewport()->update(); + viewPrivate->fullUpdatePending = 1; + continue; + default: + break; + } + + if (uninitializedDirtyRect) { + dirtyRect = adjustedItemBoundingRect(item); + if (!item->d_ptr->dirty) { + _q_adjustRect(&item->d_ptr->needsRepaint); + dirtyRect &= item->d_ptr->needsRepaint; + } + + if (item->d_ptr->dirtyChildren && !item->d_ptr->children.isEmpty() + && !item->d_ptr->childrenClippedToShape()) { + QRectF childrenBounds = item->childrenBoundingRect(); + _q_adjustRect(&childrenBounds); + dirtyRect |= childrenBounds; + } + uninitializedDirtyRect = false; + } + + if (item->d_ptr->paintedViewBoundingRectsNeedRepaint) + viewPrivate->updateRect(item->d_ptr->paintedViewBoundingRects.value(viewPrivate->viewport)); + + if (!item->d_ptr->hasBoundingRegionGranularity) + viewPrivate->updateRect(viewPrivate->mapToViewRect(item, dirtyRect)); + else + viewPrivate->updateRegion(viewPrivate->mapToViewRegion(item, dirtyRect)); + } + resetDirtyItem(item); } - dirtyItems.clear(); - dirtyItemResetPending = false; -} -/*! - \internal -*/ -void QGraphicsScenePrivate::resetDirtyItemsLater() -{ - Q_Q(QGraphicsScene); - if (dirtyItemResetPending) - return; - // dirtyItems.reserve(indexedItems.size() + unindexedItems.size()); - dirtyItemResetPending = true; - QMetaObject::invokeMethod(q, "_q_resetDirtyItems", Qt::QueuedConnection); + dirtyItems.clear(); + for (int i = 0; i < views.size(); ++i) + views.at(i)->d_func()->processPendingUpdates(); } /*! @@ -761,10 +810,9 @@ void QGraphicsScenePrivate::_q_removeItemLater(QGraphicsItem *item) // Update selected & hovered item bookkeeping selectedItems.remove(item); hoverItems.removeAll(item); - pendingUpdateItems.removeAll(item); cachedItemsUnderMouse.removeAll(item); unpolishedItems.removeAll(item); - dirtyItems.removeAll(item); + removeFromDirtyItems(item); //We remove all references of item from the sceneEventFilter arrays QMultiMap::iterator iterator = sceneEventFilters.begin(); @@ -3319,7 +3367,7 @@ void QGraphicsScene::removeItem(QGraphicsItem *item) d->pendingUpdateItems.removeAll(item); d->cachedItemsUnderMouse.removeAll(item); d->unpolishedItems.removeAll(item); - d->dirtyItems.removeAll(item); + d->removeFromDirtyItems(item); //We remove all references of item from the sceneEventFilter arrays QMultiMap::iterator iterator = d->sceneEventFilters.begin(); @@ -3330,11 +3378,6 @@ void QGraphicsScene::removeItem(QGraphicsItem *item) ++iterator; } - - //Ensure dirty flag have the correct default value so the next time it will be added it will receive updates - item->d_func()->dirty = 0; - item->d_func()->dirtyChildren = 0; - // Remove all children recursively foreach (QGraphicsItem *child, item->children()) removeItem(child); @@ -5050,7 +5093,9 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * } QRectF brect = item->boundingRect(); _q_adjustRect(&brect); - viewBoundingRect = transform.mapRect(brect).toRect().adjusted(-1, -1, 1, 1) & exposedRegion.boundingRect(); + const QRect paintedViewBoundingRect = transform.mapRect(brect).toRect().adjusted(-1, -1, 1, 1); + item->d_ptr->paintedViewBoundingRects.insert(widget, paintedViewBoundingRect); + viewBoundingRect = paintedViewBoundingRect & exposedRegion.boundingRect(); } else { transform = parentTransform; } @@ -5117,6 +5162,44 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * painter->restore(); } +void QGraphicsScenePrivate::markDirty(QGraphicsItem *item, const QRectF &rect, bool invalidateChildren, + bool maybeDirtyClipPath, bool force, bool ignoreOpacity) +{ + Q_ASSERT(item); + if (updateAll) + return; + + if (item->d_ptr->discardUpdateRequest(/*ignoreClipping=*/maybeDirtyClipPath, + /*ignoreVisibleBit=*/force, + /*ignoreDirtyBit=*/false, ignoreOpacity)) { + return; + } + + const bool fullItemUpdate = rect.isNull(); + if (!fullItemUpdate && rect.isEmpty()) + return; + + if (dirtyItems.isEmpty()) + QMetaObject::invokeMethod(q_ptr, "_q_processDirtyItems", Qt::QueuedConnection); + + if (item->d_ptr->inDirtyList) { + if (fullItemUpdate) + item->d_ptr->dirty = 1; + else if (!item->d_ptr->dirty) + item->d_ptr->needsRepaint |= rect; + } else { + dirtyItems.append(item); + item->d_ptr->inDirtyList = 1; + if (fullItemUpdate) + item->d_ptr->dirty = 1; + else if (!item->d_ptr->dirty) + item->d_ptr->needsRepaint = rect; + } + + if (invalidateChildren) + item->d_ptr->dirtyChildren = 1; +} + /*! Paints the given \a items using the provided \a painter, after the background has been drawn, and before the foreground has been @@ -5238,6 +5321,8 @@ void QGraphicsScene::drawItems(QPainter *painter, // Draw the item d->drawItemHelper(item, painter, &options[i], widget, d->painterStateProtection); + const QRect paintedViewBoundingRect = painter->worldTransform().mapRect(options[i].rect).adjusted(-1, -1, 1, 1); + item->d_ptr->paintedViewBoundingRects.insert(widget, paintedViewBoundingRect); if (saveState) painter->restore(); @@ -5364,73 +5449,6 @@ bool QGraphicsScene::focusNextPrevChild(bool next) */ /*! - \internal - - This private function is called by QGraphicsItem, which is a friend of - QGraphicsScene. It is used by QGraphicsScene to record the rectangles that - need updating. It also launches a single-shot timer to ensure that - updated() will be emitted later. - - The \a item parameter is the item that changed, and \a rect is the - area of the item that changed given in item coordinates. -*/ -void QGraphicsScene::itemUpdated(QGraphicsItem *item, const QRectF &rect) -{ - Q_D(QGraphicsScene); - // Deliver the actual update. - if (!d->updateAll) { - if (d->views.isEmpty() || ((d->connectedSignals & d->changedSignalMask) && !item->d_ptr->itemIsUntransformable() - && qFuzzyIsNull(item->boundingRegionGranularity()))) { - // This block of code is kept for compatibility. Since 4.5, by default - // QGraphicsView does not connect the signal and we use the below - // method of delivering updates. - update(item->sceneBoundingRect()); - } else { - // ### Remove _q_adjustedRects(). - QRectF boundingRect(adjustedItemBoundingRect(item)); - if (!rect.isNull()) { - QRectF adjustedRect(rect); - _q_adjustRect(&adjustedRect); - boundingRect &= adjustedRect; - } - - // Update each view directly. - for (int i = 0; i < d->views.size(); ++i) - d->views.at(i)->d_func()->itemUpdated(item, boundingRect); - } - } - if (item->d_ptr->dirty) { - d->dirtyItems << item; - d->resetDirtyItemsLater(); - } - - if (!item->isVisible()) - return; // Hiding an item won't effect the largestUntransformableItem/sceneRect. - - // Update d->largestUntransformableItem by mapping this item's bounding - // rect back to the topmost untransformable item's untransformed - // coordinate system (which sort of equals the 1:1 coordinate system of an - // untransformed view). - if (item->d_ptr->itemIsUntransformable()) { - QGraphicsItem *parent = item; - while (parent && (parent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorIgnoresTransformations)) - parent = parent->parentItem(); - d->largestUntransformableItem |= item->mapToItem(parent, item->boundingRect()).boundingRect(); - } - - // Only track the automatically growing scene rect if the scene has no - // defined scene rect. - if (!d->hasSceneRect) { - QRectF oldGrowingItemsBoundingRect = d->growingItemsBoundingRect; - QRectF adjustedItemSceneBoundingRect(item->sceneBoundingRect()); - _q_adjustRect(&adjustedItemSceneBoundingRect); - d->growingItemsBoundingRect |= adjustedItemSceneBoundingRect; - if (d->growingItemsBoundingRect != oldGrowingItemsBoundingRect) - emit sceneRectChanged(d->growingItemsBoundingRect); - } -} - -/*! \since 4.4 Returns the scene's style, or the same as QApplication::style() if the diff --git a/src/gui/graphicsview/qgraphicsscene.h b/src/gui/graphicsview/qgraphicsscene.h index 9802f87..4c0f2ec 100644 --- a/src/gui/graphicsview/qgraphicsscene.h +++ b/src/gui/graphicsview/qgraphicsscene.h @@ -271,8 +271,6 @@ Q_SIGNALS: void selectionChanged(); private: - void itemUpdated(QGraphicsItem *item, const QRectF &rect); - Q_DECLARE_PRIVATE(QGraphicsScene) Q_DISABLE_COPY(QGraphicsScene) Q_PRIVATE_SLOT(d_func(), void _q_updateIndex()) @@ -281,7 +279,7 @@ private: Q_PRIVATE_SLOT(d_func(), void _q_updateLater()) Q_PRIVATE_SLOT(d_func(), void _q_polishItems()) Q_PRIVATE_SLOT(d_func(), void _q_updateSortCache()) - Q_PRIVATE_SLOT(d_func(), void _q_resetDirtyItems()) + Q_PRIVATE_SLOT(d_func(), void _q_processDirtyItems()) friend class QGraphicsItem; friend class QGraphicsItemPrivate; friend class QGraphicsView; diff --git a/src/gui/graphicsview/qgraphicsscene_p.h b/src/gui/graphicsview/qgraphicsscene_p.h index bb99908..f2226bf 100644 --- a/src/gui/graphicsview/qgraphicsscene_p.h +++ b/src/gui/graphicsview/qgraphicsscene_p.h @@ -111,7 +111,7 @@ public: QSet selectedItems; QList unindexedItems; QList indexedItems; - QList dirtyItems; + QVector dirtyItems; QList pendingUpdateItems; QList unpolishedItems; QList topLevelItems; @@ -121,9 +121,7 @@ public: void _q_updateLater(); void _q_polishItems(); - void _q_resetDirtyItems(); - void resetDirtyItemsLater(); - bool dirtyItemResetPending; + void _q_processDirtyItems(); QList freeItemIndexes; bool regenerateIndex; @@ -257,6 +255,30 @@ public: void drawSubtreeRecursive(QGraphicsItem *item, QPainter *painter, const QTransform &parentTransform, const QTransform &viewTransform, const QRegion &exposedRegion, QWidget *widget, QGraphicsView::OptimizationFlags optimizationFlags); + void markDirty(QGraphicsItem *item, const QRectF &rect = QRectF(), bool invalidateChildren = false, + bool maybeDirtyClipPath = false, bool force = false, bool ignoreOpacity = false); + + inline void resetDirtyItem(QGraphicsItem *item) + { + Q_ASSERT(item); + item->d_ptr->dirty = 0; + item->d_ptr->paintedViewBoundingRectsNeedRepaint = 0; + item->d_ptr->dirtyChildren = 0; + item->d_ptr->inDirtyList = 0; + item->d_ptr->needsRepaint = QRectF(); + } + + inline void removeFromDirtyItems(QGraphicsItem *item) + { + int i = 0; + while (i < dirtyItems.size()) { + if (dirtyItems.at(i) == item) + dirtyItems.remove(i); + else + ++i; + } + resetDirtyItem(item); + } QStyle *style; QFont font; diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp index 1994675..acf26e1 100644 --- a/src/gui/graphicsview/qgraphicsview.cpp +++ b/src/gui/graphicsview/qgraphicsview.cpp @@ -329,8 +329,6 @@ QGraphicsViewPrivate::QGraphicsViewPrivate() #endif lastDragDropEvent(0), fullUpdatePending(true), - dirtyRectCount(0), - updatingLater(false), updateSceneSlotReimplementedChecked(false) { styleOptions.reserve(QGRAPHICSVIEW_PREALLOC_STYLE_OPTIONS); @@ -804,125 +802,28 @@ static inline QRectF adjustedItemBoundingRect(const QGraphicsItem *item) return boundingRect; } -/*! - \internal -*/ -void QGraphicsViewPrivate::itemUpdated(QGraphicsItem *item, const QRectF &rect) +void QGraphicsViewPrivate::processPendingUpdates() { - if (fullUpdatePending || viewportUpdateMode == QGraphicsView::NoViewportUpdate) - return; - if (item->d_ptr->dirty) - updateLater(); - - QRectF updateRect = rect; - if ((item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape) || item->d_ptr->children.isEmpty()) { - updateRect &= adjustedItemBoundingRect(item); - if (updateRect.isEmpty()) - return; - } - - QGraphicsItem *clipItem = item; - if (item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren) { - // Minimize unnecessary redraw. - 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) - & adjustedItemBoundingRect(parent); - if (updateRect.isEmpty()) - return; - clipItem = parent; - } - - if (!(parent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren)) - break; - } - } - - // Map update rect from clipItem coordinates to view coordinates. - Q_ASSERT(clipItem); - if (!item->d_ptr->hasBoundingRegionGranularity) - this->updateRect(mapToViewRect(clipItem, updateRect) & viewport->rect()); - else - updateRegion(mapToViewRegion(clipItem, updateRect) & viewport->rect()); -} - -void QGraphicsViewPrivate::updateLater() -{ - Q_Q(QGraphicsView); - if (updatingLater) - return; - updatingLater = true; - QMetaObject::invokeMethod(q, "_q_updateLaterSlot", Qt::QueuedConnection); -} - -void QGraphicsViewPrivate::_q_updateLaterSlot() -{ - Q_Q(QGraphicsView); if (!scene) return; - QRect vr = viewport->rect(); - QTransform viewTransform = q->viewportTransform(); - 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(/*ignoreClipping=*/false, - /*ignoreVisibleBit=*/false, - /*ignoreDirtyBit=*/true)) { - continue; - } - QTransform x = item->sceneTransform() * viewTransform; - updateRect(x.mapRect(item->boundingRect()).toAlignedRect() & vr); + if (fullUpdatePending) { // We have already called viewport->update() + dirtyBoundingRect = QRect(); + dirtyRegion = QRegion(); + return; } - dirtyRectCount += dirtyRects.size(); - - bool noUpdate = !fullUpdatePending && viewportUpdateMode == QGraphicsView::FullViewportUpdate; - if ((dirtyRectCount > 0 || !dirtyBoundingRect.isEmpty()) && !fullUpdatePending && !noUpdate) { - if (viewportUpdateMode == QGraphicsView::BoundingRectViewportUpdate - || (viewportUpdateMode == QGraphicsView::SmartViewportUpdate - && dirtyRectCount >= QGRAPHICSVIEW_REGION_RECT_THRESHOLD)) { - if (!(optimizationFlags & QGraphicsView::DontAdjustForAntialiasing)) { - viewport->update(dirtyBoundingRect.adjusted(-2, -2, 2, 2)); - } else { - viewport->update(dirtyBoundingRect); - } - } else { - // ### Improve this block, which is very slow for complex regions. We - // need to strike the balance between having an accurate update - // region, and running fast. The below approach is the simplest way to - // create a region from a bunch of rects, but we might want to use - // other approaches; e.g., a grid of a fixed size representing - // quadrants of the viewport, which we mark as dirty depending on the - // rectangles in the list. Perhaps this should go into a - // QRegion::fromRects(rects, how) function. - QRegion region; - if (!(optimizationFlags & QGraphicsView::DontAdjustForAntialiasing)) { - for (int i = 0; i < dirtyRegions.size(); ++i) { - QVector rects = dirtyRegions.at(i).rects(); - for (int j = 0; j < rects.size(); ++j) - region += rects.at(j).adjusted(-2, -2, 2, 2); - } - for (int i = 0; i < dirtyRects.size(); ++i) - region += dirtyRects.at(i).adjusted(-2, -2, 2, 2); - } else { - for (int i = 0; i < dirtyRegions.size(); ++i) - region += dirtyRegions.at(i); - for (int i = 0; i < dirtyRects.size(); ++i) - region += dirtyRects.at(i); - } - - viewport->update(region); - } + if (viewportUpdateMode == QGraphicsView::BoundingRectViewportUpdate) { + if (optimizationFlags & QGraphicsView::DontAdjustForAntialiasing) + viewport->update(dirtyBoundingRect); + else + viewport->update(dirtyBoundingRect.adjusted(-2, -2, 2, 2)); + } else { + viewport->update(dirtyRegion); // Already adjusted in updateRect/Region. } - dirtyRegions.clear(); - dirtyRects.clear(); - dirtyRectCount = 0; dirtyBoundingRect = QRect(); - updatingLater = false; + dirtyRegion = QRegion(); } void QGraphicsViewPrivate::updateAll() @@ -930,14 +831,13 @@ void QGraphicsViewPrivate::updateAll() Q_Q(QGraphicsView); q->viewport()->update(); fullUpdatePending = true; - dirtyRectCount = 0; dirtyBoundingRect = QRect(); - updatingLater = false; + dirtyRegion = QRegion(); } void QGraphicsViewPrivate::updateRegion(const QRegion &r) { - if (r.isEmpty()) + if (r.isEmpty() || fullUpdatePending) return; Q_Q(QGraphicsView); @@ -950,45 +850,30 @@ void QGraphicsViewPrivate::updateRegion(const QRegion &r) break; case QGraphicsView::BoundingRectViewportUpdate: dirtyBoundingRect |= r.boundingRect(); - if (dirtyBoundingRect == q->viewport()->rect()) { + if (dirtyBoundingRect.contains(q->viewport()->rect())) { fullUpdatePending = true; q->viewport()->update(); - } else { - updateLater(); } break; - case QGraphicsView::SmartViewportUpdate: - dirtyBoundingRect |= r.boundingRect(); - if ((dirtyRectCount + r.numRects()) < QGRAPHICSVIEW_REGION_RECT_THRESHOLD) - dirtyRegions << r; - dirtyRectCount += r.numRects(); - updateLater(); - break; + case QGraphicsView::SmartViewportUpdate: // ### DEPRECATE case QGraphicsView::MinimalViewportUpdate: - dirtyRegions << r; - dirtyRectCount += r.numRects(); - updateLater(); + if (optimizationFlags & QGraphicsView::DontAdjustForAntialiasing) { + dirtyRegion += r; + } else { + const QVector &rects = r.rects(); + for (int i = 0; i < rects.size(); ++i) + dirtyRegion += rects.at(i).adjusted(-2, -2, 2, 2); + } break; case QGraphicsView::NoViewportUpdate: // Unreachable break; } - - // Compress the regions... - if (dirtyRectCount > QGRAPHICSVIEW_REGION_RECT_THRESHOLD && dirtyRegions.size() > 1) { - QRegion masterRegion; - for (int i=0; iviewport()->rect()) { + if (dirtyBoundingRect.contains(q->viewport()->rect())) { fullUpdatePending = true; q->viewport()->update(); - } else { - updateLater(); } break; - case QGraphicsView::SmartViewportUpdate: - dirtyBoundingRect |= r; - if ((dirtyRectCount + dirtyRects.size()) < QGRAPHICSVIEW_REGION_RECT_THRESHOLD) - dirtyRects << r; - updateLater(); - break; + case QGraphicsView::SmartViewportUpdate: // ### DEPRECATE case QGraphicsView::MinimalViewportUpdate: - dirtyRects << r; - updateLater(); + if (optimizationFlags & QGraphicsView::DontAdjustForAntialiasing) + dirtyRegion += r; + else + dirtyRegion += r.adjusted(-2, -2, 2, 2); break; case QGraphicsView::NoViewportUpdate: // Unreachable @@ -2613,9 +2493,10 @@ void QGraphicsView::updateScene(const QList &rects) // Extract and reset dirty scene rect info. QVector dirtyViewportRects; - for (int i = 0; i < d->dirtyRegions.size(); ++i) - dirtyViewportRects += d->dirtyRegions.at(i).rects(); - d->dirtyRegions.clear(); + const QVector &dirtyRects = d->dirtyRegion.rects(); + for (int i = 0; i < dirtyRects.size(); ++i) + dirtyViewportRects += dirtyRects.at(i); + d->dirtyRegion = QRegion(); bool fullUpdate = !d->accelerateScrolling || d->viewportUpdateMode == QGraphicsView::FullViewportUpdate; bool boundingRectUpdate = (d->viewportUpdateMode == QGraphicsView::BoundingRectViewportUpdate) @@ -3544,10 +3425,7 @@ void QGraphicsView::scrollContentsBy(int dx, int dy) if (d->viewportUpdateMode != QGraphicsView::NoViewportUpdate) { if (d->viewportUpdateMode != QGraphicsView::FullViewportUpdate) { - for (int i = 0; i < d->dirtyRects.size(); ++i) - d->dirtyRects[i].translate(dx, dy); - for (int i = 0; i < d->dirtyRegions.size(); ++i) - d->dirtyRegions[i].translate(dx, dy); + d->dirtyRegion.translate(dx, dy); if (d->accelerateScrolling) { #ifndef QT_NO_RUBBERBAND // Update new and old rubberband regions diff --git a/src/gui/graphicsview/qgraphicsview.h b/src/gui/graphicsview/qgraphicsview.h index 7692e16..deed1d0 100644 --- a/src/gui/graphicsview/qgraphicsview.h +++ b/src/gui/graphicsview/qgraphicsview.h @@ -274,7 +274,6 @@ private: Q_PRIVATE_SLOT(d_func(), void _q_setViewportCursor(const QCursor &)) Q_PRIVATE_SLOT(d_func(), void _q_unsetViewportCursor()) #endif - Q_PRIVATE_SLOT(d_func(), void _q_updateLaterSlot()) friend class QGraphicsSceneWidget; friend class QGraphicsScene; friend class QGraphicsScenePrivate; diff --git a/src/gui/graphicsview/qgraphicsview_p.h b/src/gui/graphicsview/qgraphicsview_p.h index c18f85d..637687b 100644 --- a/src/gui/graphicsview/qgraphicsview_p.h +++ b/src/gui/graphicsview/qgraphicsview_p.h @@ -159,15 +159,10 @@ public: QRect mapToViewRect(const QGraphicsItem *item, const QRectF &rect) const; QRegion mapToViewRegion(const QGraphicsItem *item, const QRectF &rect) const; - void itemUpdated(QGraphicsItem *item, const QRectF &rect); bool fullUpdatePending; - QList dirtyRects; - QList dirtyRegions; - int dirtyRectCount; + QRegion dirtyRegion; QRect dirtyBoundingRect; - void updateLater(); - bool updatingLater; - void _q_updateLaterSlot(); + void processPendingUpdates(); void updateAll(); void updateRect(const QRect &rect); void updateRegion(const QRegion ®ion); diff --git a/tests/auto/qgraphicsscene/tst_qgraphicsscene.cpp b/tests/auto/qgraphicsscene/tst_qgraphicsscene.cpp index 0c5ebf6..23d7a94 100644 --- a/tests/auto/qgraphicsscene/tst_qgraphicsscene.cpp +++ b/tests/auto/qgraphicsscene/tst_qgraphicsscene.cpp @@ -1317,8 +1317,9 @@ void tst_QGraphicsScene::removeItem() scene.removeItem(hoverItem); hoverItem->setAcceptsHoverEvents(false); scene.addItem(hoverItem); - qApp->processEvents(); // update - qApp->processEvents(); // draw + qApp->processEvents(); // <- delayed update is called + qApp->processEvents(); // <- scene schedules pending update + qApp->processEvents(); // <- pending update is sent to view QVERIFY(!hoverItem->isHovered); } -- cgit v0.12 From 8afef542ead463b6937ec907c0b35a7977ed4a83 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Thu, 28 May 2009 10:13:12 +0200 Subject: simplify and cleanup handling of transformations in QGraphicsItem Removed some experimental code to handle scaling and rotating around different axis. It cuased setTransform and transform not to behave symmetrically and caused some performance regressions. Additionally moved the QTransform out of the (relatively slow) extra list and made it a pointer in QGraphicsItemPrivate. Reviewed-by: Andreas --- src/gui/graphicsview/qgraphicsitem.cpp | 429 ++------------------------------- src/gui/graphicsview/qgraphicsitem.h | 37 +-- src/gui/graphicsview/qgraphicsitem_p.h | 12 +- src/gui/graphicsview/qgraphicswidget.h | 9 +- 4 files changed, 23 insertions(+), 464 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index ec6b35b..14658cf 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -1102,6 +1102,9 @@ QGraphicsItem::~QGraphicsItem() if (d_ptr->scene) d_ptr->scene->d_func()->_q_removeItemLater(this); + if (d_ptr->transform) + delete d_ptr->transform; + delete d_ptr; qt_dataStore()->data.remove(this); @@ -2627,403 +2630,9 @@ QMatrix QGraphicsItem::matrix() const */ QTransform QGraphicsItem::transform() const { - if (!d_ptr->hasTransform) + if (!d_ptr->hasTransform || !d_ptr->transform) return QTransform(); - if (d_ptr->hasDecomposedTransform && d_ptr->dirtyTransform) { - QGraphicsItemPrivate::DecomposedTransform *decomposed = d_ptr->decomposedTransform(); - QTransform x; - decomposed->generateTransform(&x); - QVariant v(x); - d_ptr->setExtra(QGraphicsItemPrivate::ExtraTransform, v); - d_ptr->dirtyTransform = 0; - const_cast(this)->itemChange(ItemTransformHasChanged, v); - return x; - } - return qVariantValue(d_ptr->extra(QGraphicsItemPrivate::ExtraTransform)); -} - -/*! - \since 4.6 - - Returns the rotation around the X axis. - - The default is 0 - - \warning setting this property is conflicting with calling setTransform. - If a transform has been set, this function return the default value. - - \sa setXRotation(), {Transformations} -*/ -qreal QGraphicsItem::xRotation() const -{ - return d_ptr->decomposedTransform()->xRotation; -} - -/*! - \since 4.6 - - Sets the rotation around the X axis to \a angle degrees. - - \warning setting this property is conflicting with calling setTransform. - If a transform has been set, it will be overwritten. - - \sa xRotation(), {Transformations} -*/ -void QGraphicsItem::setXRotation(qreal angle) -{ - if (!d_ptr->dirtyTransform) { - d_ptr->fullUpdateHelper(true); - prepareGeometryChange(); - } - QGraphicsItemPrivate::DecomposedTransform *decomposed = d_ptr->decomposedTransform(); - decomposed->xRotation = angle; - if (!d_ptr->dirtyTransform) - d_ptr->invalidateSceneTransformCache(); - d_ptr->dirtyTransform = 1; - d_ptr->hasTransform = 1; -} - -/*! - \since 4.6 - - Returns the rotation around the Y axis. - - The default is 0 - - \warning setting this property is conflicting with calling setTransform. - If a transform has been set, this function return the default value. - - \sa setYRotation(), {Transformations} -*/ -qreal QGraphicsItem::yRotation() const -{ - return d_ptr->decomposedTransform()->yRotation; -} - -/*! - \since 4.6 - - Sets the rotation around the Y axis to \a angle degrees. - - \warning setting this property is conflicting with calling setTransform. - If a transform has been set, it will be overwritten. - - \sa yRotation(), {Transformations} -*/ -void QGraphicsItem::setYRotation(qreal angle) -{ - if (!d_ptr->dirtyTransform) { - d_ptr->fullUpdateHelper(true); - prepareGeometryChange(); - } - QGraphicsItemPrivate::DecomposedTransform *decomposed = d_ptr->decomposedTransform(); - decomposed->yRotation = angle; - if (!d_ptr->dirtyTransform) - d_ptr->invalidateSceneTransformCache(); - d_ptr->dirtyTransform = 1; - d_ptr->hasTransform = 1; -} - -/*! - \since 4.6 - - Returns the rotation around the Z axis. - - The default is 0 - - \warning setting this property is conflicting with calling setTransform. - If a transform has been set, this function return the default value. - - \sa setZRotation(), {Transformations} -*/ -qreal QGraphicsItem::zRotation() const -{ - return d_ptr->decomposedTransform()->zRotation; -} - -/*! - \since 4.6 - - Sets the rotation around the Z axis to \a angle degrees. - - \warning setting this property is conflicting with calling setTransform. - If a transform has been set, it will be overwritten. - - \sa zRotation(), {Transformations} -*/ -void QGraphicsItem::setZRotation(qreal angle) -{ - if (!d_ptr->dirtyTransform) { - d_ptr->fullUpdateHelper(true); - prepareGeometryChange(); - } - QGraphicsItemPrivate::DecomposedTransform *decomposed = d_ptr->decomposedTransform(); - decomposed->zRotation = angle; - if (!d_ptr->dirtyTransform) - d_ptr->invalidateSceneTransformCache(); - d_ptr->dirtyTransform = 1; - d_ptr->hasTransform = 1; -} - -/*! - \since 4.6 - - This convenience function set the rotation angles around the 3 axes - to \a x, \a y and \a z. - - \sa setXRotation(), setYRotation(), setZRotation() -*/ -void QGraphicsItem::setRotation(qreal x, qreal y, qreal z) -{ - setXRotation(x); - setYRotation(y); - setZRotation(z); -} - -/*! - \since 4.6 - - Returns the scale factor on the X axis. - - The default is 1 - - \warning setting this property is conflicting with calling setTransform. - If a transform has been set, this function return the default value. - - \sa setXScale(), {Transformations} -*/ -qreal QGraphicsItem::xScale() const -{ - return d_ptr->decomposedTransform()->xScale; -} - -/*! - \since 4.6 - - Sets the scale factor on the X axis to \a factor. - - \warning setting this property is conflicting with calling setTransform. - If a transform has been set, it will be overwritten. - - \sa xScale(), {Transformations} -*/ -void QGraphicsItem::setXScale(qreal factor) -{ - if (!d_ptr->dirtyTransform) { - d_ptr->fullUpdateHelper(true); - prepareGeometryChange(); - } - QGraphicsItemPrivate::DecomposedTransform *decomposed = d_ptr->decomposedTransform(); - decomposed->xScale = factor; - if (!d_ptr->dirtyTransform) - d_ptr->invalidateSceneTransformCache(); - d_ptr->dirtyTransform = 1; - d_ptr->hasTransform = 1; -} - -/*! - \since 4.6 - - Returns the scale factor on the Y axis. - - The default is 1 - - \warning setting this property is conflicting with calling setTransform. - If a transform has been set, this function return the default value. - - \sa setYScale(), {Transformations} -*/ -qreal QGraphicsItem::yScale() const -{ - return d_ptr->decomposedTransform()->yScale; -} - -/*! - \since 4.6 - - Sets the scale factor on the Y axis to \a factor. - - \warning setting this property is conflicting with calling setTransform. - If a transform has been set, it will be overwritten. - - \sa yScale(), {Transformations} -*/ -void QGraphicsItem::setYScale(qreal factor) -{ - if (!d_ptr->dirtyTransform) { - d_ptr->fullUpdateHelper(true); - prepareGeometryChange(); - } - QGraphicsItemPrivate::DecomposedTransform *decomposed = d_ptr->decomposedTransform(); - decomposed->yScale = factor; - if (!d_ptr->dirtyTransform) - d_ptr->invalidateSceneTransformCache(); - d_ptr->dirtyTransform = 1; - d_ptr->hasTransform = 1; -} - -/*! - \since 4.6 - - This convenience function set the scaling factors on X and Y axis to \a sx and \a sy. - - \sa setXScale(), setYScale() -*/ -void QGraphicsItem::setScale(qreal sx, qreal sy) -{ - setXScale(sx); - setYScale(sy); -} - -/*! - \since 4.6 - - Returns the horizontal shear. - - The default is 0 - - \warning setting this property is conflicting with calling setTransform. - If a transform has been set, this function return the default value. - - \sa setHorizontalShear(), {Transformations} -*/ -qreal QGraphicsItem::horizontalShear() const -{ - return d_ptr->decomposedTransform()->horizontalShear; -} - -/*! - \since 4.6 - - Sets the horizontal shear to \a shear. - - \warning setting this property is conflicting with calling setTransform. - If a transform has been set, it will be overwritten. - - \sa horizontalShear(), {Transformations} -*/ -void QGraphicsItem::setHorizontalShear(qreal shear) -{ - if (!d_ptr->dirtyTransform) { - d_ptr->fullUpdateHelper(true); - prepareGeometryChange(); - } - QGraphicsItemPrivate::DecomposedTransform *decomposed = d_ptr->decomposedTransform(); - decomposed->horizontalShear = shear; - if (!d_ptr->dirtyTransform) - d_ptr->invalidateSceneTransformCache(); - d_ptr->dirtyTransform = 1; - d_ptr->hasTransform = 1; -} - -/*! - \since 4.6 - - Returns the vertical shear. - - The default is 0 - - \warning setting this property is conflicting with calling setTransform. - If a transform has been set, this function return the default value. - - \sa setHorizontalShear(), {Transformations} -*/ -qreal QGraphicsItem::verticalShear() const -{ - return d_ptr->decomposedTransform()->verticalShear; -} - -/*! - \since 4.6 - - Sets the vertical shear to \a shear. - - \warning setting this property is conflicting with calling setTransform. - If a transform has been set, it will be overwritten. - - \sa verticalShear(), {Transformations} -*/ -void QGraphicsItem::setVerticalShear(qreal shear) -{ - if (!d_ptr->dirtyTransform) { - d_ptr->fullUpdateHelper(true); - prepareGeometryChange(); - } - QGraphicsItemPrivate::DecomposedTransform *decomposed = d_ptr->decomposedTransform(); - decomposed->verticalShear = shear; - if (!d_ptr->dirtyTransform) - d_ptr->invalidateSceneTransformCache(); - d_ptr->dirtyTransform = 1; - d_ptr->hasTransform = 1; -} - -/*! - \since 4.6 - - This convenience function sets the horizontal shear to \a sh and the vertical shear to \a sv. - - \sa setHorizontalShear(), setVerticalShear() -*/ -void QGraphicsItem::setShear(qreal sh, qreal sv) -{ - setHorizontalShear(sh); - setVerticalShear(sv); -} - -/*! - \since 4.6 - - Returns the transformation origin for the transformation properties. - - The default is QPointF(0,0). - - \warning setting this property is conflicting with calling setTransform. - If a transform has been set, this function return the default value. - - \sa setTransformOrigin(), {Transformations} -*/ -QPointF QGraphicsItem::transformOrigin() const -{ - const QGraphicsItemPrivate::DecomposedTransform *decomposed = d_ptr->decomposedTransform(); - return QPointF(decomposed->xOrigin, decomposed->yOrigin); -} - -/*! - \fn inline void setTransformOrigin(qreal x, qreal y) - - \since 4.6 - - This is an overloaded member function, provided for convenience. - Sets the transformation origin for the transformation - properties to the point(\a x, \a y). - - \sa setTransformOrigin(), {Transformations} -*/ - -/*! - \since 4.6 - - Sets the transformation origin for the transformation properties to \a origin. - This does not apply to the transformation set by setTransform. - - \warning setting this property is conflicting with calling setTransform. - If a transform has been set, it will be overwritten. - - \sa transformOrigin(), {Transformations} -*/ -void QGraphicsItem::setTransformOrigin(const QPointF &origin) -{ - if (!d_ptr->dirtyTransform) { - d_ptr->fullUpdateHelper(true); - prepareGeometryChange(); - } - QGraphicsItemPrivate::DecomposedTransform *decomposed = d_ptr->decomposedTransform(); - decomposed->xOrigin = origin.x(); - decomposed->yOrigin = origin.y(); - if (!d_ptr->dirtyTransform) - d_ptr->invalidateSceneTransformCache(); - d_ptr->dirtyTransform = 1; - d_ptr->hasTransform = 1; + return *d_ptr->transform; } /*! @@ -3306,11 +2915,7 @@ QTransform QGraphicsItem::itemTransform(const QGraphicsItem *other, bool *ok) co void QGraphicsItem::setMatrix(const QMatrix &matrix, bool combine) { QTransform oldTransform = this->transform(); - QTransform newTransform; - if (!combine) - newTransform = QTransform(matrix); - else - newTransform = QTransform(matrix) * oldTransform; + QTransform newTransform(combine ? QTransform(matrix) * oldTransform : QTransform(matrix)); if (oldTransform == newTransform) return; @@ -3324,9 +2929,10 @@ void QGraphicsItem::setMatrix(const QMatrix &matrix, bool combine) // Update and set the new transformation. prepareGeometryChange(); d_ptr->hasTransform = !newTransform.isIdentity(); - d_ptr->setExtra(QGraphicsItemPrivate::ExtraTransform, newTransform); - d_ptr->dirtyTransformComponents = 1; - d_ptr->dirtyTransform = 0; + if(!d_ptr->transform) + d_ptr->transform = new QTransform(newTransform); + else + *d_ptr->transform = newTransform; d_ptr->invalidateSceneTransformCache(); // Send post-notification. @@ -3358,11 +2964,7 @@ void QGraphicsItem::setMatrix(const QMatrix &matrix, bool combine) void QGraphicsItem::setTransform(const QTransform &matrix, bool combine) { QTransform oldTransform = this->transform(); - QTransform newTransform; - if (!combine) - newTransform = matrix; - else - newTransform = matrix * oldTransform; + QTransform newTransform(combine ? matrix * oldTransform : matrix); if (oldTransform == newTransform) return; @@ -3376,9 +2978,10 @@ void QGraphicsItem::setTransform(const QTransform &matrix, bool combine) // Update and set the new transformation. prepareGeometryChange(); d_ptr->hasTransform = !newTransform.isIdentity(); - d_ptr->setExtra(QGraphicsItemPrivate::ExtraTransform, newTransform); - d_ptr->dirtyTransformComponents = 1; - d_ptr->dirtyTransform = 0; + if(!d_ptr->transform) + d_ptr->transform = new QTransform(newTransform); + else + *d_ptr->transform = newTransform; d_ptr->invalidateSceneTransformCache(); // Send post-notification. @@ -6359,7 +5962,7 @@ void QGraphicsItem::prepareGeometryChange() } QGraphicsItem *parent = this; - while (parent = parent->d_ptr->parent) + while ((parent = parent->d_ptr->parent)) parent->d_ptr->dirtyChildrenBoundingRect = 1; if (d_ptr->inSetPosHelper) diff --git a/src/gui/graphicsview/qgraphicsitem.h b/src/gui/graphicsview/qgraphicsitem.h index f6ee197..def773e 100644 --- a/src/gui/graphicsview/qgraphicsitem.h +++ b/src/gui/graphicsview/qgraphicsitem.h @@ -242,39 +242,10 @@ public: void setTransform(const QTransform &matrix, bool combine = false); void resetTransform(); - void rotate(qreal angle); // ### obsolete - void scale(qreal sx, qreal sy); // ### obsolete - void shear(qreal sh, qreal sv); // ### obsolete - void translate(qreal dx, qreal dy); // ### obsolete - - qreal xRotation() const; - void setXRotation(qreal angle); - - qreal yRotation() const; - void setYRotation(qreal angle); - - qreal zRotation() const; - void setZRotation(qreal angle); - void setRotation(qreal x, qreal y, qreal z); - - qreal xScale() const; - void setXScale(qreal factor); - - qreal yScale() const; - void setYScale(qreal factor); - void setScale(qreal sx, qreal sy); - - qreal horizontalShear() const; - void setHorizontalShear(qreal shear); - - qreal verticalShear() const; - void setVerticalShear(qreal shear); - void setShear(qreal sh, qreal sv); - - QPointF transformOrigin() const; - void setTransformOrigin(const QPointF &origin); - inline void setTransformOrigin(qreal x, qreal y) - { setTransformOrigin(QPointF(x,y)); } + void rotate(qreal angle); + void scale(qreal sx, qreal sy); + void shear(qreal sh, qreal sv); + void translate(qreal dx, qreal dy); virtual void advance(int phase); diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index 1d4b37a..5c7e67c 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -95,17 +95,7 @@ class Q_AUTOTEST_EXPORT QGraphicsItemPrivate { Q_DECLARE_PUBLIC(QGraphicsItem) public: - struct TransformData - { - TransformData() : rotationX(0),rotationY(0),rotationZ(0),scaleX(1),scaleY(1), dirty(true) {} - QTransform baseTransform; - QTransform transform; - QPointF transformCenter; - qreal rotationX,rotationY,rotationZ,scaleX,scaleY; - bool dirty; - }; enum Extra { - ExtraTransform, ExtraToolTip, ExtraCursor, ExtraCacheData, @@ -127,6 +117,7 @@ public: : z(0), scene(0), parent(0), + transform(0), siblingIndex(-1), index(-1), depth(0), @@ -329,6 +320,7 @@ public: QGraphicsScene *scene; QGraphicsItem *parent; QList children; + QTransform *transform; int siblingIndex; int index; int depth; diff --git a/src/gui/graphicsview/qgraphicswidget.h b/src/gui/graphicsview/qgraphicswidget.h index a5c9068..34f1c5f 100644 --- a/src/gui/graphicsview/qgraphicswidget.h +++ b/src/gui/graphicsview/qgraphicswidget.h @@ -81,14 +81,7 @@ class Q_GUI_EXPORT QGraphicsWidget : public QObject, public QGraphicsItem, publi Q_PROPERTY(qreal opacity READ opacity WRITE setOpacity) Q_PROPERTY(QPointF pos READ pos WRITE setPos) Q_PROPERTY(QRectF geometry READ geometry WRITE setGeometry) - Q_PROPERTY(QPointF transformOrigin READ transformOrigin WRITE setTransformOrigin) - Q_PROPERTY(qreal xRotation READ xRotation WRITE setXRotation) - Q_PROPERTY(qreal yRotation READ yRotation WRITE setYRotation) - Q_PROPERTY(qreal zRotation READ zRotation WRITE setZRotation) - Q_PROPERTY(qreal xScale READ xScale WRITE setXScale) - Q_PROPERTY(qreal yScale READ yScale WRITE setYScale) - Q_PROPERTY(qreal horizontalShear READ horizontalShear WRITE setHorizontalShear) - Q_PROPERTY(qreal verticalShear READ verticalShear WRITE setVerticalShear) + public: QGraphicsWidget(QGraphicsItem *parent = 0, Qt::WindowFlags wFlags = 0); ~QGraphicsWidget(); -- cgit v0.12 From 5ea28946b53b001a6fcbc1c382f80f798ac6ab4b Mon Sep 17 00:00:00 2001 From: Andreas Aardal Hanssen Date: Thu, 28 May 2009 11:31:24 +0200 Subject: Remove scene transform cache from QGraphicsItem. Now that we have a recursive painting algorithm these types of optimizations are no longer necessary. In fact they only cause more problems and clutter up the code unnecessarily. Removing this also removes extra overhead from moving and transforming items. Reviewed-by: Lars --- src/gui/graphicsview/qgraphicsitem.cpp | 64 +++++---------------------------- src/gui/graphicsview/qgraphicsitem_p.h | 3 -- src/gui/graphicsview/qgraphicsscene.cpp | 17 ++------- src/gui/graphicsview/qgraphicsscene_p.h | 4 --- 4 files changed, 10 insertions(+), 78 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index 14658cf..c1848e0 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -918,9 +918,6 @@ void QGraphicsItemPrivate::setParentItemHelper(QGraphicsItem *newParent, bool de // Resolve depth. resolveDepth(parent ? parent->d_ptr->depth : -1); - // Invalidate transform cache. - invalidateSceneTransformCache(); - // Deliver post-change notification q->itemChange(QGraphicsItem::ItemParentHasChanged, newParentVariant); } @@ -2526,7 +2523,6 @@ void QGraphicsItemPrivate::setPosHelper(const QPointF &pos) if (scene) q->prepareGeometryChange(); this->pos = newPos; - invalidateSceneTransformCache(); // Send post-notification. q->itemChange(QGraphicsItem::ItemPositionHasChanged, newPosVariant); @@ -2667,44 +2663,15 @@ QMatrix QGraphicsItem::sceneMatrix() const */ QTransform QGraphicsItem::sceneTransform() const { - // Check if there's any entry in the transform cache. - QGraphicsScenePrivate *sd = d_ptr->scene ? d_ptr->scene->d_func() : 0; - int index = d_ptr->sceneTransformIndex; - if (sd && index != -1 && sd->validTransforms.testBit(index)) - return sd->sceneTransformCache[index]; - - // Calculate local transform. QTransform m; - if (d_ptr->hasTransform) { - m = transform(); - 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. - if (d_ptr->parent) { - m *= d_ptr->parent->sceneTransform(); - // Don't cache toplevels - if (sd) { - if (index == -1) { - if (!sd->freeSceneTransformSlots.isEmpty()) { - index = sd->freeSceneTransformSlots.last(); - sd->freeSceneTransformSlots.pop_back(); - } else { - index = sd->sceneTransformCache.size(); - } - d_ptr->sceneTransformIndex = index; - if (index >= sd->validTransforms.size()) { - sd->validTransforms.resize(index + 1); - sd->sceneTransformCache.resize(index + 1); - } - } - sd->validTransforms.setBit(index, 1); - sd->sceneTransformCache[index] = m; - } - } + const QGraphicsItem *p = this; + do { + if (p->d_ptr->hasTransform) + m *= p->transform(); + const QPointF &pos = p->d_ptr->pos; + if (!pos.isNull()) + m *= QTransform::fromTranslate(pos.x(), pos.y()); + } while ((p = p->d_ptr->parent)); return m; } @@ -2933,7 +2900,6 @@ void QGraphicsItem::setMatrix(const QMatrix &matrix, bool combine) d_ptr->transform = new QTransform(newTransform); else *d_ptr->transform = newTransform; - d_ptr->invalidateSceneTransformCache(); // Send post-notification. // NB! We have to change the value from QMatrix to QTransform. @@ -2982,7 +2948,6 @@ void QGraphicsItem::setTransform(const QTransform &matrix, bool combine) d_ptr->transform = new QTransform(newTransform); else *d_ptr->transform = newTransform; - d_ptr->invalidateSceneTransformCache(); // Send post-notification. itemChange(ItemTransformHasChanged, newTransformVariant); @@ -3912,19 +3877,6 @@ void QGraphicsItemPrivate::resolveDepth(int parentDepth) /*! \internal */ -void QGraphicsItemPrivate::invalidateSceneTransformCache() -{ - if (!scene || (parent && sceneTransformIndex == -1)) - return; - if (sceneTransformIndex != -1) - scene->d_func()->validTransforms.setBit(sceneTransformIndex, 0); - for (int i = 0; i < children.size(); ++i) - children.at(i)->d_ptr->invalidateSceneTransformCache(); -} - -/*! - \internal -*/ void QGraphicsItemPrivate::addChild(QGraphicsItem *child) { child->d_ptr->siblingIndex = children.size(); diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index 5c7e67c..5a6401a 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -155,7 +155,6 @@ public: inDirtyList(0), paintedViewBoundingRectsNeedRepaint(0), globalStackingOrder(-1), - sceneTransformIndex(-1), q_ptr(0) { } @@ -182,7 +181,6 @@ public: void updateEffectiveOpacity(); void resolveEffectiveOpacity(qreal effectiveParentOpacity); void resolveDepth(int parentDepth); - void invalidateSceneTransformCache(); void addChild(QGraphicsItem *child); void removeChild(QGraphicsItem *child); void setParentItemHelper(QGraphicsItem *parent, bool deleting); @@ -365,7 +363,6 @@ public: // Optional stacking order int globalStackingOrder; - int sceneTransformIndex; struct DecomposedTransform; DecomposedTransform *decomposedTransform() const diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index d004ed2..86e7cdb 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -823,13 +823,6 @@ void QGraphicsScenePrivate::_q_removeItemLater(QGraphicsItem *item) ++iterator; } - // Remove from scene transform cache - int transformIndex = item->d_func()->sceneTransformIndex; - if (transformIndex != -1) { - validTransforms.setBit(transformIndex, 0); - freeSceneTransformSlots.append(transformIndex); - } - // Reset the mouse grabber if (mouseGrabberItems.contains(item)) ungrabMouse(item, /* item is dying */ true); @@ -3340,14 +3333,6 @@ void QGraphicsScene::removeItem(QGraphicsItem *item) d->unindexedItems.removeAll(item); } - // Remove from scene transform cache - int transformIndex = item->d_func()->sceneTransformIndex; - if (transformIndex != -1) { - d->validTransforms.setBit(transformIndex, 0); - d->freeSceneTransformSlots.append(transformIndex); - item->d_func()->sceneTransformIndex = -1; - } - if (item == d->focusItem) d->focusItem = 0; if (item == d->lastFocusItem) @@ -3817,6 +3802,8 @@ bool QGraphicsScene::event(QEvent *event) // items from inside event handlers, this list can quickly end up // having stale pointers in it. We need to clear it before dispatching // events that use it. + // ### this should only be cleared if we received a new mouse move event, + // which relies on us fixing the replay mechanism in QGraphicsView. d->cachedItemsUnderMouse.clear(); default: break; diff --git a/src/gui/graphicsview/qgraphicsscene_p.h b/src/gui/graphicsview/qgraphicsscene_p.h index f2226bf..bf7ac0a 100644 --- a/src/gui/graphicsview/qgraphicsscene_p.h +++ b/src/gui/graphicsview/qgraphicsscene_p.h @@ -289,10 +289,6 @@ public: void setPalette_helper(const QPalette &palette); void resolvePalette(); void updatePalette(const QPalette &palette); - - mutable QVector sceneTransformCache; - mutable QBitArray validTransforms; - mutable QVector freeSceneTransformSlots; }; QT_END_NAMESPACE -- cgit v0.12 From f233dafed58b6429d693ae0248f596a0377cd547 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Thu, 28 May 2009 12:25:21 +0200 Subject: get rid of the hasTransform flag in QGraphicsItem Since the transform is now a pointer in QGraphicsItemPrivate, we can use this pointer directly and there's no need for a separate bitflag anymore. Reviewed-by: Andreas --- src/gui/graphicsview/qgraphicsitem.cpp | 81 ++++++++++++++++----------------- src/gui/graphicsview/qgraphicsitem_p.h | 3 +- src/gui/graphicsview/qgraphicsscene.cpp | 16 +++---- src/gui/graphicsview/qgraphicsview.cpp | 2 +- 4 files changed, 48 insertions(+), 54 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index c1848e0..26da858 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -937,12 +937,11 @@ void QGraphicsItemPrivate::childrenBoundingRectHelper(QTransform *x, QRectF *rec for (int i = 0; i < children.size(); ++i) { QGraphicsItem *child = children.at(i); QGraphicsItemPrivate *childd = child->d_ptr; - bool hasX = childd->hasTransform; bool hasPos = !childd->pos.isNull(); - if (hasPos || hasX) { + if (hasPos || childd->transform) { QTransform matrix; - if (hasX) - matrix = child->transform(); + if (childd->transform) + matrix = *childd->transform; if (hasPos) { const QPointF &p = childd->pos; matrix *= QTransform::fromTranslate(p.x(), p.y()); @@ -2626,7 +2625,7 @@ QMatrix QGraphicsItem::matrix() const */ QTransform QGraphicsItem::transform() const { - if (!d_ptr->hasTransform || !d_ptr->transform) + if (!d_ptr->transform) return QTransform(); return *d_ptr->transform; } @@ -2666,8 +2665,8 @@ QTransform QGraphicsItem::sceneTransform() const QTransform m; const QGraphicsItem *p = this; do { - if (p->d_ptr->hasTransform) - m *= p->transform(); + if (p->d_ptr->transform) + m *= *p->d_ptr->transform; const QPointF &pos = p->d_ptr->pos; if (!pos.isNull()) m *= QTransform::fromTranslate(pos.x(), pos.y()); @@ -2777,17 +2776,17 @@ QTransform QGraphicsItem::itemTransform(const QGraphicsItem *other, bool *ok) co *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 d_ptr->transform ? *d_ptr->transform : QTransform(); + if (d_ptr->transform) + return *d_ptr->transform * QTransform::fromTranslate(itemPos.x(), itemPos.y()); return QTransform::fromTranslate(itemPos.x(), itemPos.y()); } // This is other's parent if (otherParent == this) { const QPointF &otherPos = other->d_ptr->pos; - if (other->d_ptr->hasTransform) { - QTransform otherToParent = other->transform(); + if (other->d_ptr->transform) { + QTransform otherToParent = *other->d_ptr->transform; if (!otherPos.isNull()) otherToParent *= QTransform::fromTranslate(otherPos.x(), otherPos.y()); return otherToParent.inverted(ok); @@ -2800,12 +2799,10 @@ QTransform QGraphicsItem::itemTransform(const QGraphicsItem *other, bool *ok) co // Siblings if (parent == otherParent) { - bool hasTr = d_ptr->hasTransform; - bool otherHasTr = other->d_ptr->hasTransform; const QPointF &itemPos = d_ptr->pos; const QPointF &otherPos = other->d_ptr->pos; - if (!hasTr && !otherHasTr) { + if (!d_ptr->transform && !other->d_ptr->transform) { QPointF delta = itemPos - otherPos; if (ok) *ok = true; @@ -2813,12 +2810,12 @@ QTransform QGraphicsItem::itemTransform(const QGraphicsItem *other, bool *ok) co } QTransform itemToParent = QTransform::fromTranslate(itemPos.x(), itemPos.y()); - if (hasTr) - itemToParent = itemPos.isNull() ? transform() : transform() * itemToParent; + if (d_ptr->transform) + itemToParent = itemPos.isNull() ? *d_ptr->transform : *d_ptr->transform * itemToParent; QTransform otherToParent = QTransform::fromTranslate(otherPos.x(), otherPos.y()); - if (otherHasTr) - otherToParent = otherPos.isNull() ? other->transform() : other->transform() * otherToParent; + if (other->d_ptr->transform) + otherToParent = otherPos.isNull() ? *other->d_ptr->transform : *other->d_ptr->transform * otherToParent; return itemToParent * otherToParent.inverted(ok); } @@ -2856,8 +2853,8 @@ QTransform QGraphicsItem::itemTransform(const QGraphicsItem *other, bool *ok) co const QGraphicsItem *p = child; do { const QGraphicsItemPrivate *pd = p->d_ptr; - if (pd->hasTransform) - x *= p->transform(); + if (pd->transform) + x *= *pd->transform; if (!pd->pos.isNull()) x *= QTransform::fromTranslate(pd->pos.x(), pd->pos.y()); } while ((p = p->d_ptr->parent) && p != root); @@ -2895,7 +2892,6 @@ void QGraphicsItem::setMatrix(const QMatrix &matrix, bool combine) // Update and set the new transformation. prepareGeometryChange(); - d_ptr->hasTransform = !newTransform.isIdentity(); if(!d_ptr->transform) d_ptr->transform = new QTransform(newTransform); else @@ -2943,7 +2939,6 @@ void QGraphicsItem::setTransform(const QTransform &matrix, bool combine) // Update and set the new transformation. prepareGeometryChange(); - d_ptr->hasTransform = !newTransform.isIdentity(); if(!d_ptr->transform) d_ptr->transform = new QTransform(newTransform); else @@ -3214,7 +3209,7 @@ QRectF QGraphicsItem::sceneBoundingRect() const const QGraphicsItemPrivate *itemd; do { itemd = parentItem->d_ptr; - if (itemd->hasTransform) + if (itemd->transform) break; offset += itemd->pos; } while ((parentItem = itemd->parent)); @@ -3984,13 +3979,13 @@ void QGraphicsItemPrivate::updateCachedClipPathFromSetPosHelper(const QPointF &n // Find closest clip ancestor and transform. Q_Q(QGraphicsItem); - QTransform thisToParentTransform = hasTransform - ? q->transform() * QTransform::fromTranslate(newPos.x(), newPos.y()) + QTransform thisToParentTransform = transform + ? *transform * QTransform::fromTranslate(newPos.x(), newPos.y()) : QTransform::fromTranslate(newPos.x(), newPos.y()); QGraphicsItem *clipParent = parent; while (clipParent && !(clipParent->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape)) { - if (clipParent->d_ptr->hasTransform) - thisToParentTransform *= clipParent->transform(); + if (clipParent->d_ptr->transform) + thisToParentTransform *= *clipParent->d_ptr->transform; if (!clipParent->d_ptr->pos.isNull()) { thisToParentTransform *= QTransform::fromTranslate(clipParent->d_ptr->pos.x(), clipParent->d_ptr->pos.y()); @@ -4357,9 +4352,9 @@ QPointF QGraphicsItem::mapToItem(const QGraphicsItem *item, const QPointF &point */ QPointF QGraphicsItem::mapToParent(const QPointF &point) const { - if (!d_ptr->hasTransform) + if (!d_ptr->transform) return point + d_ptr->pos; - return transform().map(point) + d_ptr->pos; + return d_ptr->transform->map(point) + d_ptr->pos; } /*! @@ -4424,9 +4419,9 @@ QPolygonF QGraphicsItem::mapToItem(const QGraphicsItem *item, const QRectF &rect */ QPolygonF QGraphicsItem::mapToParent(const QRectF &rect) const { - if (!d_ptr->hasTransform) + if (!d_ptr->transform) return rect.translated(d_ptr->pos); - return transform().map(rect).translated(d_ptr->pos); + return d_ptr->transform->map(rect).translated(d_ptr->pos); } /*! @@ -4493,7 +4488,7 @@ QRectF QGraphicsItem::mapRectToItem(const QGraphicsItem *item, const QRectF &rec */ QRectF QGraphicsItem::mapRectToParent(const QRectF &rect) const { - QRectF r = !d_ptr->hasTransform ? rect : transform().mapRect(rect); + QRectF r = !d_ptr->transform ? rect : d_ptr->transform->mapRect(rect); return r.translated(d_ptr->pos); } @@ -4566,7 +4561,7 @@ QRectF QGraphicsItem::mapRectFromItem(const QGraphicsItem *item, const QRectF &r QRectF QGraphicsItem::mapRectFromParent(const QRectF &rect) const { QRectF r = rect.translated(-d_ptr->pos); - return d_ptr->hasTransform ? transform().inverted().mapRect(r) : r; + return d_ptr->transform ? d_ptr->transform->inverted().mapRect(r) : r; } /*! @@ -4625,9 +4620,9 @@ QPolygonF QGraphicsItem::mapToItem(const QGraphicsItem *item, const QPolygonF &p */ QPolygonF QGraphicsItem::mapToParent(const QPolygonF &polygon) const { - if (!d_ptr->hasTransform) + if (!d_ptr->transform) return polygon.translated(d_ptr->pos); - return transform().map(polygon).translated(d_ptr->pos); + return d_ptr->transform->map(polygon).translated(d_ptr->pos); } /*! @@ -4669,9 +4664,9 @@ QPainterPath QGraphicsItem::mapToItem(const QGraphicsItem *item, const QPainterP */ QPainterPath QGraphicsItem::mapToParent(const QPainterPath &path) const { - if (!d_ptr->hasTransform) + if (!d_ptr->transform) return path.translated(d_ptr->pos); - return transform().map(path).translated(d_ptr->pos); + return d_ptr->transform->map(path).translated(d_ptr->pos); } /*! @@ -4720,8 +4715,8 @@ QPointF QGraphicsItem::mapFromItem(const QGraphicsItem *item, const QPointF &poi */ QPointF QGraphicsItem::mapFromParent(const QPointF &point) const { - if (d_ptr->hasTransform) - return transform().inverted().map(point - d_ptr->pos); + if (d_ptr->transform) + return d_ptr->transform->inverted().map(point - d_ptr->pos); return point - d_ptr->pos; } @@ -4789,7 +4784,7 @@ QPolygonF QGraphicsItem::mapFromItem(const QGraphicsItem *item, const QRectF &re QPolygonF QGraphicsItem::mapFromParent(const QRectF &rect) const { QRectF r = rect.translated(-d_ptr->pos); - return d_ptr->hasTransform ? transform().inverted().map(r) : r; + return d_ptr->transform ? d_ptr->transform->inverted().map(r) : r; } /*! @@ -4846,7 +4841,7 @@ QPolygonF QGraphicsItem::mapFromParent(const QPolygonF &polygon) const { QPolygonF p = polygon; p.translate(-d_ptr->pos); - return d_ptr->hasTransform ? transform().inverted().map(p) : p; + return d_ptr->transform ? d_ptr->transform->inverted().map(p) : p; } /*! @@ -4888,7 +4883,7 @@ QPainterPath QGraphicsItem::mapFromParent(const QPainterPath &path) const { QPainterPath p(path); p.translate(-d_ptr->pos); - return d_ptr->hasTransform ? transform().inverted().map(p) : p; + return d_ptr->transform ? d_ptr->transform->inverted().map(p) : p; } /*! diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index 5a6401a..35305b4 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -132,7 +132,6 @@ public: isMemberOfGroup(0), handlesChildEvents(0), itemDiscovered(0), - hasTransform(0), hasCursor(0), ancestorFlags(0), cacheMode(0), @@ -335,7 +334,6 @@ public: quint32 isMemberOfGroup : 1; quint32 handlesChildEvents : 1; quint32 itemDiscovered : 1; - quint32 hasTransform : 1; quint32 hasCursor : 1; quint32 ancestorFlags : 3; quint32 cacheMode : 2; @@ -349,6 +347,7 @@ public: quint32 dirtyClipPath : 1; quint32 emptyClipPath : 1; quint32 inSetPosHelper : 1; + quint32 unused : 1; // New 32 bits quint32 flags : 10; diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index 86e7cdb..b105c9c 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -1679,7 +1679,7 @@ void QGraphicsScenePrivate::childItems_helper(QList *items, 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()) + if (item->d_ptr->transform && !item->d_ptr->transform->isInvertible()) continue; // Skip invisible items and all their children. @@ -1719,7 +1719,7 @@ void QGraphicsScenePrivate::childItems_helper(QList *items, 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()) + if (item->d_ptr->transform && !item->d_ptr->transform->isInvertible()) continue; // Skip invisible items and all their children. @@ -1755,7 +1755,7 @@ void QGraphicsScenePrivate::childItems_helper(QList *items, if ((keep || !(item->flags() & QGraphicsItem::ItemClipsChildrenToShape)) && !item->d_ptr->children.isEmpty()) { // Recurse into children. - if (!item->d_ptr->hasTransform || item->transform().type() <= QTransform::TxScale) { + if (!item->d_ptr->transform || item->d_ptr->transform->type() <= QTransform::TxScale) { // Rect childItems_helper(items, item, item->mapRectFromParent(rect), mode); } else { @@ -1785,7 +1785,7 @@ void QGraphicsScenePrivate::childItems_helper(QList *items, 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()) + if (item->d_ptr->transform && !item->d_ptr->transform->isInvertible()) continue; // Skip invisible items. @@ -1844,7 +1844,7 @@ void QGraphicsScenePrivate::childItems_helper(QList *items, 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()) + if (item->d_ptr->transform && !item->d_ptr->transform->isInvertible()) continue; // Skip invisible items. @@ -5065,9 +5065,9 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * } else { const QPointF &pos = item->d_ptr->pos; bool posNull = pos.isNull(); - if (!posNull || item->d_ptr->hasTransform) { - if (item->d_ptr->hasTransform) { - QTransform x = item->transform(); + if (!posNull || item->d_ptr->transform) { + if (item->d_ptr->transform) { + QTransform x = *item->d_ptr->transform; if (!posNull) x *= QTransform::fromTranslate(pos.x(), pos.y()); transform = x * parentTransform; diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp index acf26e1..68c0e39 100644 --- a/src/gui/graphicsview/qgraphicsview.cpp +++ b/src/gui/graphicsview/qgraphicsview.cpp @@ -753,7 +753,7 @@ QRect QGraphicsViewPrivate::mapToViewRect(const QGraphicsItem *item, const QRect const QGraphicsItemPrivate *itemd; do { itemd = parentItem->d_ptr; - if (itemd->hasTransform) + if (itemd->transform) break; offset += itemd->pos; } while ((parentItem = itemd->parent)); -- cgit v0.12 From 7c164da956c3b55b6b38df1c9e13dcd821b5062f Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Thu, 28 May 2009 15:31:46 +0200 Subject: simplify opacity handling in QGraphicsItem Greatly simplify how we handle opacity and store it as a member in QGraphicsItemPrivate. Remove the caching of effectiveOpacity. It's faster to calculate it on the fly, and the recursive painting algorithm will make even that need go away. Reviewed-by: Andreas --- src/gui/graphicsview/qgraphicsitem.cpp | 114 +++++---------------------------- src/gui/graphicsview/qgraphicsitem_p.h | 28 ++++---- 2 files changed, 31 insertions(+), 111 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index 26da858..3f6b83c 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -912,9 +912,6 @@ void QGraphicsItemPrivate::setParentItemHelper(QGraphicsItem *newParent, bool de scene->d_func()->invalidateSortCache(); } - // Resolve opacity. - updateEffectiveOpacity(); - // Resolve depth. resolveDepth(parent ? parent->d_ptr->depth : -1); @@ -1372,11 +1369,6 @@ void QGraphicsItem::setFlags(GraphicsItemFlags flags) // Update flags. d_ptr->flags = flags; - // Reresolve effective opacity if the opacity flags change. - static const quint32 opacityFlagsMask = ItemIgnoresParentOpacity | ItemDoesntPropagateOpacityToChildren; - if ((flags & opacityFlagsMask) != (oldFlags & opacityFlagsMask)) - d_ptr->updateEffectiveOpacity(); - if (!(d_ptr->flags & ItemIsFocusable) && hasFocus()) { // Clear focus on the item if it has focus when the focusable flag // is unset. @@ -1981,12 +1973,7 @@ void QGraphicsItem::setSelected(bool selected) */ qreal QGraphicsItem::opacity() const { - if (d_ptr->hasOpacity) { - QVariant o = d_ptr->extra(QGraphicsItemPrivate::ExtraOpacity); - if (!o.isNull()) - return o.toDouble(); - } - return qreal(1.0); + return d_ptr->opacity; } /*! @@ -2002,11 +1989,20 @@ qreal QGraphicsItem::opacity() const */ qreal QGraphicsItem::effectiveOpacity() const { - if (!d_ptr->hasEffectiveOpacity) - return qreal(1.0); + if (!d_ptr->parent) + return d_ptr->opacity; + + QGraphicsItem::GraphicsItemFlags myFlags = flags(); + QGraphicsItem::GraphicsItemFlags parentFlags = d_ptr->parent ? d_ptr->parent->flags() : QGraphicsItem::GraphicsItemFlags(0); + + // If I have a parent, and I don't ignore my parent's opacity, and my + // parent propagates to me, then combine my local opacity with my parent's + // effective opacity into my effective opacity. + if (!(myFlags & QGraphicsItem::ItemIgnoresParentOpacity) + && !(parentFlags & QGraphicsItem::ItemDoesntPropagateOpacityToChildren)) + return d_ptr->opacity * d_ptr->parent->effectiveOpacity(); - QVariant effectiveOpacity = d_ptr->extra(QGraphicsItemPrivate::ExtraEffectiveOpacity); - return effectiveOpacity.isNull() ? qreal(1.0) : qreal(effectiveOpacity.toDouble()); + return d_ptr->opacity; } /*! @@ -2041,24 +2037,10 @@ void QGraphicsItem::setOpacity(qreal opacity) newOpacity = qBound(0.0, newOpacity, 1.0); // No change? Done. - if (qFuzzyIsNull(newOpacity - this->opacity())) + if (newOpacity == d_ptr->opacity) return; - // Assign local opacity. - if (qFuzzyIsNull(newOpacity - 1)) { - // Opaque, unset opacity. - d_ptr->hasOpacity = 0; - d_ptr->unsetExtra(QGraphicsItemPrivate::ExtraOpacity); - } else { - d_ptr->hasOpacity = 1; - d_ptr->setExtra(QGraphicsItemPrivate::ExtraOpacity, double(newOpacity)); - } - - // Resolve effective opacity. - if (QGraphicsItem *p = d_ptr->parent) - d_ptr->resolveEffectiveOpacity(p->effectiveOpacity()); - else - d_ptr->resolveEffectiveOpacity(1.0); + d_ptr->opacity = newOpacity; // Notify change. itemChange(ItemOpacityHasChanged, newOpacity); @@ -3793,70 +3775,6 @@ bool QGraphicsItemPrivate::discardUpdateRequest(bool ignoreClipping, bool ignore || (!ignoreOpacity && childrenCombineOpacity() && isFullyTransparent()); } -static inline bool allChildrenCombineOpacityHelper(QGraphicsItem *parent) -{ - Q_ASSERT(parent); - if (parent->flags() & QGraphicsItem::ItemDoesntPropagateOpacityToChildren) - return false; - - const QList children(parent->childItems()); - for (int i = 0; i < children.size(); ++i) { - if (children.at(i)->flags() & QGraphicsItem::ItemIgnoresParentOpacity) - return false; - } - return true; -} - -void QGraphicsItemPrivate::updateEffectiveOpacity() -{ - Q_Q(QGraphicsItem); - if (parent) { - resolveEffectiveOpacity(parent->effectiveOpacity()); - parent->d_ptr->allChildrenCombineOpacity = allChildrenCombineOpacityHelper(parent); - } else { - resolveEffectiveOpacity(1.0); - } - allChildrenCombineOpacity = allChildrenCombineOpacityHelper(q); -} - -/*! - \internal - - Resolves and propagates this item's effective opacity to its children. -*/ -void QGraphicsItemPrivate::resolveEffectiveOpacity(qreal parentEffectiveOpacity) -{ - Q_Q(QGraphicsItem); - QGraphicsItem::GraphicsItemFlags myFlags = q->flags(); - QGraphicsItem::GraphicsItemFlags parentFlags = parent ? parent->flags() : QGraphicsItem::GraphicsItemFlags(0); - - // My local opacity is always part of my effective opacity. - qreal myEffectiveOpacity = q->opacity(); - - // If I have a parent, and I don't ignore my parent's opacity, and my - // parent propagates to me, then combine my local opacity with my parent's - // effective opacity into my effective opacity. - if (parent - && !(myFlags & QGraphicsItem::ItemIgnoresParentOpacity) - && !(parentFlags & QGraphicsItem::ItemDoesntPropagateOpacityToChildren)) { - myEffectiveOpacity *= parentEffectiveOpacity; - } - - // Set this item's resolved opacity. - if (qFuzzyIsNull(myEffectiveOpacity - 1)) { - // 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) - children.at(i)->d_ptr->resolveEffectiveOpacity(myEffectiveOpacity); -} - /*! \internal diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index 35305b4..c999378 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -100,10 +100,7 @@ public: ExtraCursor, ExtraCacheData, ExtraMaxDeviceCoordCacheSize, - ExtraBoundingRegionGranularity, - ExtraOpacity, - ExtraEffectiveOpacity, - ExtraDecomposedTransform + ExtraBoundingRegionGranularity }; enum AncestorFlag { @@ -115,6 +112,7 @@ public: inline QGraphicsItemPrivate() : z(0), + opacity(1.), scene(0), parent(0), transform(0), @@ -136,8 +134,6 @@ public: ancestorFlags(0), cacheMode(0), hasBoundingRegionGranularity(0), - hasOpacity(0), - hasEffectiveOpacity(0), isWidget(0), dirty(0), dirtyChildren(0), @@ -177,8 +173,6 @@ public: void setEnabledHelper(bool newEnabled, bool explicitly, bool update = true); bool discardUpdateRequest(bool ignoreClipping = false, bool ignoreVisibleBit = false, bool ignoreDirtyBit = false, bool ignoreOpacity = false) const; - void updateEffectiveOpacity(); - void resolveEffectiveOpacity(qreal effectiveParentOpacity); void resolveDepth(int parentDepth); void addChild(QGraphicsItem *child); void removeChild(QGraphicsItem *child); @@ -278,10 +272,19 @@ public: void updateCachedClipPathFromSetPosHelper(const QPointF &newPos); inline bool isFullyTransparent() const - { return hasEffectiveOpacity && qFuzzyIsNull(q_func()->effectiveOpacity()); } + { return q_func()->effectiveOpacity() < .001; } inline bool childrenCombineOpacity() const - { return allChildrenCombineOpacity || children.isEmpty(); } + { + if (!children.size() || flags & QGraphicsItem::ItemDoesntPropagateOpacityToChildren) + return false; + + for (int i = 0; i < children.size(); ++i) { + if (children.at(i)->d_ptr->flags & QGraphicsItem::ItemIgnoresParentOpacity) + return false; + } + return true; + } inline bool isClippedAway() const { return !dirtyClipPath && q_func()->isClipped() && (emptyClipPath || cachedClipPath.isEmpty()); } @@ -314,6 +317,7 @@ public: QMap paintedViewBoundingRects; QPointF pos; qreal z; + qreal opacity; QGraphicsScene *scene; QGraphicsItem *parent; QList children; @@ -338,8 +342,6 @@ public: quint32 ancestorFlags : 3; quint32 cacheMode : 2; quint32 hasBoundingRegionGranularity : 1; - quint32 hasOpacity : 1; - quint32 hasEffectiveOpacity : 1; quint32 isWidget : 1; quint32 dirty : 1; quint32 dirtyChildren : 1; @@ -347,7 +349,7 @@ public: quint32 dirtyClipPath : 1; quint32 emptyClipPath : 1; quint32 inSetPosHelper : 1; - quint32 unused : 1; + quint32 unused : 3; // New 32 bits quint32 flags : 10; -- cgit v0.12 From ce5b4c468d98bb4ec64429fa362554b9b3614496 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Thu, 28 May 2009 16:08:25 +0200 Subject: smaller optimisation in setTransform --- src/gui/graphicsview/qgraphicsitem.cpp | 40 +++++++++++++++------------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index 3f6b83c..486e0b5 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -2860,28 +2860,25 @@ QTransform QGraphicsItem::itemTransform(const QGraphicsItem *other, bool *ok) co */ void QGraphicsItem::setMatrix(const QMatrix &matrix, bool combine) { - QTransform oldTransform = this->transform(); - QTransform newTransform(combine ? QTransform(matrix) * oldTransform : QTransform(matrix)); - if (oldTransform == newTransform) + if(!d_ptr->transform) + d_ptr->transform = new QTransform; + + QTransform newTransform(combine ? QTransform(matrix) * *d_ptr->transform : QTransform(matrix)); + if(*d_ptr->transform == newTransform) return; - // Notify the item that the matrix is changing. - QVariant newTransformVariant(itemChange(ItemMatrixChange, - qVariantFromValue(newTransform.toAffine()))); - newTransform = QTransform(qVariantValue(newTransformVariant)); - if (oldTransform == newTransform) + // Notify the item that the transformation matrix is changing. + const QVariant newTransformVariant(itemChange(ItemTransformChange, + qVariantFromValue(newTransform))); + newTransform = qVariantValue(newTransformVariant); + if (*d_ptr->transform == newTransform) return; // Update and set the new transformation. prepareGeometryChange(); - if(!d_ptr->transform) - d_ptr->transform = new QTransform(newTransform); - else - *d_ptr->transform = newTransform; + *d_ptr->transform = newTransform; // Send post-notification. - // NB! We have to change the value from QMatrix to QTransform. - qVariantSetValue(newTransformVariant, newTransform); itemChange(ItemTransformHasChanged, newTransformVariant); } @@ -2907,24 +2904,23 @@ void QGraphicsItem::setMatrix(const QMatrix &matrix, bool combine) */ void QGraphicsItem::setTransform(const QTransform &matrix, bool combine) { - QTransform oldTransform = this->transform(); - QTransform newTransform(combine ? matrix * oldTransform : matrix); - if (oldTransform == newTransform) + if(!d_ptr->transform) + d_ptr->transform = new QTransform; + + QTransform newTransform(combine ? matrix * *d_ptr->transform : matrix); + if(*d_ptr->transform == newTransform) return; // Notify the item that the transformation matrix is changing. const QVariant newTransformVariant(itemChange(ItemTransformChange, qVariantFromValue(newTransform))); newTransform = qVariantValue(newTransformVariant); - if (oldTransform == newTransform) + if (*d_ptr->transform == newTransform) return; // Update and set the new transformation. prepareGeometryChange(); - if(!d_ptr->transform) - d_ptr->transform = new QTransform(newTransform); - else - *d_ptr->transform = newTransform; + *d_ptr->transform = newTransform; // Send post-notification. itemChange(ItemTransformHasChanged, newTransformVariant); -- cgit v0.12 From fa256ad3758e0d8794136975f0e93ddfa91216f5 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Thu, 28 May 2009 16:09:38 +0200 Subject: remove now unused flag --- src/gui/graphicsview/qgraphicsitem_p.h | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index c999378..95a7733 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -142,10 +142,6 @@ public: emptyClipPath(0), inSetPosHelper(0), flags(0), - allChildrenCombineOpacity(1), - hasDecomposedTransform(0), - dirtyTransform(0), - dirtyTransformComponents(0), dirtyChildrenBoundingRect(1), inDirtyList(0), paintedViewBoundingRectsNeedRepaint(0), @@ -353,14 +349,10 @@ public: // New 32 bits quint32 flags : 10; - quint32 allChildrenCombineOpacity : 1; - quint32 hasDecomposedTransform : 1; - quint32 dirtyTransform : 1; - quint32 dirtyTransformComponents : 1; quint32 dirtyChildrenBoundingRect : 1; quint32 inDirtyList : 1; quint32 paintedViewBoundingRectsNeedRepaint : 1; - quint32 padding : 15; // feel free to use + quint32 padding : 19; // feel free to use // Optional stacking order int globalStackingOrder; -- cgit v0.12 From 72e083c98c3adb07bb1578fb7f28f121fc3f34ac Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Thu, 28 May 2009 16:47:29 +0200 Subject: greatly speed up QTransform::mapRect() for projective transforms The code so far was converting the rect to a painterpath, mapping that one and then taking the bounding rect. It is actually sufficient to simply map the four corners of the rectangle and take the bounding rect of these four points even in the projective case. Reviewed-by: Andreas --- src/gui/painting/qtransform.cpp | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/gui/painting/qtransform.cpp b/src/gui/painting/qtransform.cpp index c00012a..86e594c 100644 --- a/src/gui/painting/qtransform.cpp +++ b/src/gui/painting/qtransform.cpp @@ -1788,7 +1788,7 @@ QRect QTransform::mapRect(const QRect &rect) const y -= h; } return QRect(x, y, w, h); - } else if (t < TxProject) { + } else { // see mapToPolygon for explanations of the algorithm. qreal x = 0, y = 0; MAP(rect.left(), rect.top(), x, y); @@ -1812,10 +1812,6 @@ QRect QTransform::mapRect(const QRect &rect) const xmax = qMax(xmax, x); ymax = qMax(ymax, y); return QRect(qRound(xmin), qRound(ymin), qRound(xmax)-qRound(xmin), qRound(ymax)-qRound(ymin)); - } else { - QPainterPath path; - path.addRect(rect); - return map(path).boundingRect().toRect(); } } @@ -1858,7 +1854,7 @@ QRectF QTransform::mapRect(const QRectF &rect) const y -= h; } return QRectF(x, y, w, h); - } else if (t < TxProject) { + } else { qreal x = 0, y = 0; MAP(rect.x(), rect.y(), x, y); qreal xmin = x; @@ -1881,10 +1877,6 @@ QRectF QTransform::mapRect(const QRectF &rect) const xmax = qMax(xmax, x); ymax = qMax(ymax, y); return QRectF(xmin, ymin, xmax-xmin, ymax - ymin); - } else { - QPainterPath path; - path.addRect(rect); - return map(path).boundingRect(); } } -- cgit v0.12 From bea8a19742ed1decbd63464e36e57980fbde7016 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Thu, 28 May 2009 22:55:49 +0200 Subject: fix a small logic bug in childrenCombineOpacity Regression introduced during refactoring earlier today. --- src/gui/graphicsview/qgraphicsitem_p.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index 95a7733..acd2fcc 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -272,7 +272,9 @@ public: inline bool childrenCombineOpacity() const { - if (!children.size() || flags & QGraphicsItem::ItemDoesntPropagateOpacityToChildren) + if (!children.size()) + return true; + if (flags & QGraphicsItem::ItemDoesntPropagateOpacityToChildren) return false; for (int i = 0; i < children.size(); ++i) { -- cgit v0.12 From c563cff78b9606bf5869707fcbe6183198508d60 Mon Sep 17 00:00:00 2001 From: Andreas Aardal Hanssen Date: Fri, 29 May 2009 08:54:31 +0200 Subject: Introduce QGraphicsItem::ItemHasNoContents. This flag helps optimize the case where an item is used only as a transformation node in a scene graph, and where the item itself doesn't paint anything. This is the default for FxItem (the subclasses that do paint enable the HasContents flag). This lets Graphics View know whether there's any point in setting up the world transform, opacity and other things. Reviewed-by: Lars --- src/gui/graphicsview/qgraphicsitem.cpp | 8 ++++++++ src/gui/graphicsview/qgraphicsitem.h | 3 ++- src/gui/graphicsview/qgraphicsitem_p.h | 4 ++-- src/gui/graphicsview/qgraphicsscene.cpp | 30 ++++++++++++++++++++---------- 4 files changed, 32 insertions(+), 13 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index 486e0b5..12aaba5 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -309,6 +309,11 @@ and is always initialized to 1. Use QStyleOptionGraphicsItem::levelOfDetailFromTransform for a more fine-grained value. + + \value ItemHasNoContents The item does not paint anything (i.e., calling + paint() on the item has no effect). You should set this flag on items that + do not need to be painted to ensure that Graphics View avoids unnecessary + painting preparations. */ /*! @@ -9108,6 +9113,9 @@ QDebug operator<<(QDebug debug, QGraphicsItem::GraphicsItemFlag flag) case QGraphicsItem::ItemUsesExtendedStyleOption: str = "ItemUsesExtendedStyleOption"; break; + case QGraphicsItem::ItemHasNoContents: + str = "ItemHasNoContents"; + break; } debug << str; return debug; diff --git a/src/gui/graphicsview/qgraphicsitem.h b/src/gui/graphicsview/qgraphicsitem.h index def773e..737ea80 100644 --- a/src/gui/graphicsview/qgraphicsitem.h +++ b/src/gui/graphicsview/qgraphicsitem.h @@ -95,7 +95,8 @@ public: ItemIgnoresParentOpacity = 0x40, ItemDoesntPropagateOpacityToChildren = 0x80, ItemStacksBehindParent = 0x100, - ItemUsesExtendedStyleOption = 0x200 + ItemUsesExtendedStyleOption = 0x200, + ItemHasNoContents = 0x400 // NB! Don't forget to increase the d_ptr->flags bit field by 1 when adding a new flag. }; Q_DECLARE_FLAGS(GraphicsItemFlags, GraphicsItemFlag) diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index acd2fcc..9d5b58a 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -350,11 +350,11 @@ public: quint32 unused : 3; // New 32 bits - quint32 flags : 10; + quint32 flags : 11; quint32 dirtyChildrenBoundingRect : 1; quint32 inDirtyList : 1; quint32 paintedViewBoundingRectsNeedRepaint : 1; - quint32 padding : 19; // feel free to use + quint32 padding : 18; // feel free to use // Optional stacking order int globalStackingOrder; diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index b105c9c..eaebd1a 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -295,9 +295,13 @@ static inline bool QRectF_intersects(const QRectF &s, const QRectF &r) static inline void _q_adjustRect(QRectF *rect) { Q_ASSERT(rect); - if (!rect->width()) + bool nullWidth = !rect->width(); + bool nullHeight = !rect->height(); + if (nullWidth && nullHeight) + return; + if (nullWidth) rect->adjust(-0.00001, 0, 0.00001, 0); - if (!rect->height()) + else if (nullHeight) rect->adjust(0, -0.00001, 0, 0.00001); } @@ -5079,22 +5083,23 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * } } QRectF brect = item->boundingRect(); - _q_adjustRect(&brect); - const QRect paintedViewBoundingRect = transform.mapRect(brect).toRect().adjusted(-1, -1, 1, 1); - item->d_ptr->paintedViewBoundingRects.insert(widget, paintedViewBoundingRect); - viewBoundingRect = paintedViewBoundingRect & exposedRegion.boundingRect(); + if (!brect.size().isNull()) { + // ### This does not take the clip into account. + _q_adjustRect(&brect); + const QRect paintedViewBoundingRect = transform.mapRect(brect).toRect().adjusted(-1, -1, 1, 1); + item->d_ptr->paintedViewBoundingRects.insert(widget, paintedViewBoundingRect); + viewBoundingRect = paintedViewBoundingRect & exposedRegion.boundingRect(); + } } else { transform = parentTransform; } - // Find and sort children. - QList children = item ? item->d_ptr->children : topLevelItems; - qSort(children.begin(), children.end(), qt_notclosestLeaf); - bool childClip = (item && (item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape)); bool dontDrawItem = !item || viewBoundingRect.isEmpty(); bool dontDrawChildren = item && dontDrawItem && childClip; childClip &= !dontDrawChildren & !children.isEmpty(); + if (item && item->d_ptr->flags & QGraphicsItem::ItemHasNoContents) + dontDrawItem = true; // Clip children. if (childClip) { @@ -5103,6 +5108,11 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * painter->setClipPath(item->shape(), Qt::IntersectClip); } + // Find and sort children. + QList children = item ? item->d_ptr->children : topLevelItems; + if (!dontDrawChildren) + qSort(children.begin(), children.end(), qt_notclosestLeaf); + // Draw children behind int i; if (!dontDrawChildren) { -- cgit v0.12 From 33c1496689c090561657c698321442ae655ccec3 Mon Sep 17 00:00:00 2001 From: Andreas Aardal Hanssen Date: Thu, 28 May 2009 11:31:24 +0200 Subject: Remove scene transform cache from QGraphicsItem. Now that we have a recursive painting algorithm these types of optimizations are no longer necessary. In fact they only cause more problems and clutter up the code unnecessarily. Removing this also removes extra overhead from moving and transforming items. Reviewed-by: Lars --- src/gui/graphicsview/qgraphicsitem.cpp | 232 +++++++++++++++++++++++++++++++++ 1 file changed, 232 insertions(+) diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index 12aaba5..0990e16 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -2652,8 +2652,13 @@ QTransform QGraphicsItem::sceneTransform() const QTransform m; const QGraphicsItem *p = this; do { +<<<<<<< HEAD:src/gui/graphicsview/qgraphicsitem.cpp if (p->d_ptr->transform) m *= *p->d_ptr->transform; +======= + if (p->d_ptr->hasTransform) + m *= p->transform(); +>>>>>>> Remove scene transform cache from QGraphicsItem.:src/gui/graphicsview/qgraphicsitem.cpp const QPointF &pos = p->d_ptr->pos; if (!pos.isNull()) m *= QTransform::fromTranslate(pos.x(), pos.y()); @@ -2881,7 +2886,13 @@ void QGraphicsItem::setMatrix(const QMatrix &matrix, bool combine) // Update and set the new transformation. prepareGeometryChange(); +<<<<<<< HEAD:src/gui/graphicsview/qgraphicsitem.cpp *d_ptr->transform = newTransform; +======= + transformData->baseTransform = newTransform; + transformData->dirty = true; + d_ptr->hasTransform = true; +>>>>>>> Remove scene transform cache from QGraphicsItem.:src/gui/graphicsview/qgraphicsitem.cpp // Send post-notification. itemChange(ItemTransformHasChanged, newTransformVariant); @@ -2925,7 +2936,14 @@ void QGraphicsItem::setTransform(const QTransform &matrix, bool combine) // Update and set the new transformation. prepareGeometryChange(); +<<<<<<< HEAD:src/gui/graphicsview/qgraphicsitem.cpp *d_ptr->transform = newTransform; +======= + transformData->baseTransform = newTransform; + transformData->dirty = true; + d_ptr->hasTransform = true; + transform(); // ### update transform, bad! +>>>>>>> Remove scene transform cache from QGraphicsItem.:src/gui/graphicsview/qgraphicsitem.cpp // Send post-notification. itemChange(ItemTransformHasChanged, newTransformVariant); @@ -3036,6 +3054,220 @@ void QGraphicsItem::translate(qreal dx, qreal dy) } /*! +<<<<<<< HEAD:src/gui/graphicsview/qgraphicsitem.cpp +======= + Returns the origin point used for all transformations. + */ +QPointF QGraphicsItem::transformOrigin() const +{ + QGraphicsItemPrivate::TransformData *transformData = static_cast( + qVariantValue(d_ptr->extra(QGraphicsItemPrivate::ExtraTransform))); + if (!transformData) + return QPointF(); + + return transformData->transformCenter; +} + +/*! + Set a \a center for all transformations. +*/ +void QGraphicsItem::setTransformOrigin(const QPointF ¢er) +{ + QGraphicsItemPrivate::TransformData *transformData = static_cast( + qVariantValue(d_ptr->extra(QGraphicsItemPrivate::ExtraTransform))); + if (!transformData) { + if (center.isNull()) + return; + transformData = new QGraphicsItemPrivate::TransformData; + d_ptr->setExtra(QGraphicsItemPrivate::ExtraTransform, qVariantFromValue(transformData)); + } + if (transformData->transformCenter == center) + return; + + prepareGeometryChange(); + + transformData->transformCenter = center; + + transformData->dirty = true; + d_ptr->hasTransform = true; +} + +/*! + Returns the x scale factor. + */ +qreal QGraphicsItem::xScale() const +{ + QGraphicsItemPrivate::TransformData *transformData = static_cast( + qVariantValue(d_ptr->extra(QGraphicsItemPrivate::ExtraTransform))); + if (!transformData) + return 1; + + return transformData->scaleX; +} + +/*! + Sets the x scale factor to \a factor. + */ +void QGraphicsItem::setXScale(qreal factor) +{ + QGraphicsItemPrivate::TransformData *transformData = static_cast( + qVariantValue(d_ptr->extra(QGraphicsItemPrivate::ExtraTransform))); + if (!transformData) { + if (factor == 1) + return; + transformData = new QGraphicsItemPrivate::TransformData; + d_ptr->setExtra(QGraphicsItemPrivate::ExtraTransform, qVariantFromValue(transformData)); + } + if (transformData->scaleX == factor) + return; + + prepareGeometryChange(); + + transformData->scaleX = factor; + transformData->dirty = true; + d_ptr->hasTransform = true; +} + +/*! + Returns the y scale factor. + */ +qreal QGraphicsItem::yScale() const +{ + QGraphicsItemPrivate::TransformData *transformData = static_cast( + qVariantValue(d_ptr->extra(QGraphicsItemPrivate::ExtraTransform))); + if (!transformData) + return 1; + + return transformData->scaleY; +} + +/*! + Sets the y scale factor to \a factor. + */ +void QGraphicsItem::setYScale(qreal factor) +{ + QGraphicsItemPrivate::TransformData *transformData = static_cast( + qVariantValue(d_ptr->extra(QGraphicsItemPrivate::ExtraTransform))); + if (!transformData) { + if (factor == 1) + return; + transformData = new QGraphicsItemPrivate::TransformData; + d_ptr->setExtra(QGraphicsItemPrivate::ExtraTransform, qVariantFromValue(transformData)); + } + if (transformData->scaleY == factor) + return; + + prepareGeometryChange(); + + transformData->scaleY = factor; + transformData->dirty = true; + d_ptr->hasTransform = true; +} + +/*! + Returns the x rotation angle. + */ +qreal QGraphicsItem::xRotation() const +{ + QGraphicsItemPrivate::TransformData *transformData = static_cast( + qVariantValue(d_ptr->extra(QGraphicsItemPrivate::ExtraTransform))); + if (!transformData) + return 0; + return transformData->rotationX; +} + +/*! + Sets the x rotation angle to \a angle. + */ +void QGraphicsItem::setXRotation(qreal angle) +{ + QGraphicsItemPrivate::TransformData *transformData = static_cast( + qVariantValue(d_ptr->extra(QGraphicsItemPrivate::ExtraTransform))); + if (!transformData) { + if (qFuzzyCompare(angle + 1, 1)) + return; + transformData = new QGraphicsItemPrivate::TransformData; + d_ptr->setExtra(QGraphicsItemPrivate::ExtraTransform, qVariantFromValue(transformData)); + } + + prepareGeometryChange(); + + transformData->rotationX = angle; + + transformData->dirty = true; + d_ptr->hasTransform = true; +} + +/*! + Returns the y rotation angle. + */ +qreal QGraphicsItem::yRotation() const +{ + QGraphicsItemPrivate::TransformData *transformData = static_cast( + qVariantValue(d_ptr->extra(QGraphicsItemPrivate::ExtraTransform))); + if (!transformData) + return 0; + return transformData->rotationY; +} + +/*! + Sets the y rotation angle to \a angle. + */ +void QGraphicsItem::setYRotation(qreal angle) +{ + QGraphicsItemPrivate::TransformData *transformData = static_cast( + qVariantValue(d_ptr->extra(QGraphicsItemPrivate::ExtraTransform))); + if (!transformData) { + if (qFuzzyCompare(angle + 1, 1)) + return; + transformData = new QGraphicsItemPrivate::TransformData; + d_ptr->setExtra(QGraphicsItemPrivate::ExtraTransform, qVariantFromValue(transformData)); + } + + prepareGeometryChange(); + + transformData->rotationY = angle; + + transformData->dirty = true; + d_ptr->hasTransform = true; +} + +/*! + Returns the z rotation angle. + */ +qreal QGraphicsItem::zRotation() const +{ + QGraphicsItemPrivate::TransformData *transformData = static_cast( + qVariantValue(d_ptr->extra(QGraphicsItemPrivate::ExtraTransform))); + if (!transformData) + return 0; + return transformData->rotationZ; +} + +/*! + Sets the z rotation angle to \a angle. + */ +void QGraphicsItem::setZRotation(qreal angle) +{ + QGraphicsItemPrivate::TransformData *transformData = static_cast( + qVariantValue(d_ptr->extra(QGraphicsItemPrivate::ExtraTransform))); + if (!transformData) { + if (qFuzzyCompare(angle + 1, 1)) + return; + transformData = new QGraphicsItemPrivate::TransformData; + d_ptr->setExtra(QGraphicsItemPrivate::ExtraTransform, qVariantFromValue(transformData)); + } + + prepareGeometryChange(); + + transformData->rotationZ = angle; + + transformData->dirty = true; + d_ptr->hasTransform = true; +} + +/*! +>>>>>>> Remove scene transform cache from QGraphicsItem.:src/gui/graphicsview/qgraphicsitem.cpp This virtual function is called twice for all items by the QGraphicsScene::advance() slot. In the first phase, all items are called with \a phase == 0, indicating that items on the scene are about to -- cgit v0.12 From e506c0816dadd336e8151a0af504bd8b814bbaf3 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Thu, 28 May 2009 12:25:21 +0200 Subject: get rid of the hasTransform flag in QGraphicsItem Since the transform is now a pointer in QGraphicsItemPrivate, we can use this pointer directly and there's no need for a separate bitflag anymore. Reviewed-by: Andreas --- src/gui/graphicsview/qgraphicsitem.cpp | 242 ++------------------------------- src/gui/graphicsview/qgraphicsitem_p.h | 2 +- 2 files changed, 9 insertions(+), 235 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index 0990e16..3008997 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -2652,13 +2652,8 @@ QTransform QGraphicsItem::sceneTransform() const QTransform m; const QGraphicsItem *p = this; do { -<<<<<<< HEAD:src/gui/graphicsview/qgraphicsitem.cpp if (p->d_ptr->transform) m *= *p->d_ptr->transform; -======= - if (p->d_ptr->hasTransform) - m *= p->transform(); ->>>>>>> Remove scene transform cache from QGraphicsItem.:src/gui/graphicsview/qgraphicsitem.cpp const QPointF &pos = p->d_ptr->pos; if (!pos.isNull()) m *= QTransform::fromTranslate(pos.x(), pos.y()); @@ -2886,13 +2881,10 @@ void QGraphicsItem::setMatrix(const QMatrix &matrix, bool combine) // Update and set the new transformation. prepareGeometryChange(); -<<<<<<< HEAD:src/gui/graphicsview/qgraphicsitem.cpp - *d_ptr->transform = newTransform; -======= - transformData->baseTransform = newTransform; - transformData->dirty = true; - d_ptr->hasTransform = true; ->>>>>>> Remove scene transform cache from QGraphicsItem.:src/gui/graphicsview/qgraphicsitem.cpp + if(!d_ptr->transform) + d_ptr->transform = new QTransform(newTransform); + else + *d_ptr->transform = newTransform; // Send post-notification. itemChange(ItemTransformHasChanged, newTransformVariant); @@ -2936,14 +2928,10 @@ void QGraphicsItem::setTransform(const QTransform &matrix, bool combine) // Update and set the new transformation. prepareGeometryChange(); -<<<<<<< HEAD:src/gui/graphicsview/qgraphicsitem.cpp - *d_ptr->transform = newTransform; -======= - transformData->baseTransform = newTransform; - transformData->dirty = true; - d_ptr->hasTransform = true; - transform(); // ### update transform, bad! ->>>>>>> Remove scene transform cache from QGraphicsItem.:src/gui/graphicsview/qgraphicsitem.cpp + if(!d_ptr->transform) + d_ptr->transform = new QTransform(newTransform); + else + *d_ptr->transform = newTransform; // Send post-notification. itemChange(ItemTransformHasChanged, newTransformVariant); @@ -3054,220 +3042,6 @@ void QGraphicsItem::translate(qreal dx, qreal dy) } /*! -<<<<<<< HEAD:src/gui/graphicsview/qgraphicsitem.cpp -======= - Returns the origin point used for all transformations. - */ -QPointF QGraphicsItem::transformOrigin() const -{ - QGraphicsItemPrivate::TransformData *transformData = static_cast( - qVariantValue(d_ptr->extra(QGraphicsItemPrivate::ExtraTransform))); - if (!transformData) - return QPointF(); - - return transformData->transformCenter; -} - -/*! - Set a \a center for all transformations. -*/ -void QGraphicsItem::setTransformOrigin(const QPointF ¢er) -{ - QGraphicsItemPrivate::TransformData *transformData = static_cast( - qVariantValue(d_ptr->extra(QGraphicsItemPrivate::ExtraTransform))); - if (!transformData) { - if (center.isNull()) - return; - transformData = new QGraphicsItemPrivate::TransformData; - d_ptr->setExtra(QGraphicsItemPrivate::ExtraTransform, qVariantFromValue(transformData)); - } - if (transformData->transformCenter == center) - return; - - prepareGeometryChange(); - - transformData->transformCenter = center; - - transformData->dirty = true; - d_ptr->hasTransform = true; -} - -/*! - Returns the x scale factor. - */ -qreal QGraphicsItem::xScale() const -{ - QGraphicsItemPrivate::TransformData *transformData = static_cast( - qVariantValue(d_ptr->extra(QGraphicsItemPrivate::ExtraTransform))); - if (!transformData) - return 1; - - return transformData->scaleX; -} - -/*! - Sets the x scale factor to \a factor. - */ -void QGraphicsItem::setXScale(qreal factor) -{ - QGraphicsItemPrivate::TransformData *transformData = static_cast( - qVariantValue(d_ptr->extra(QGraphicsItemPrivate::ExtraTransform))); - if (!transformData) { - if (factor == 1) - return; - transformData = new QGraphicsItemPrivate::TransformData; - d_ptr->setExtra(QGraphicsItemPrivate::ExtraTransform, qVariantFromValue(transformData)); - } - if (transformData->scaleX == factor) - return; - - prepareGeometryChange(); - - transformData->scaleX = factor; - transformData->dirty = true; - d_ptr->hasTransform = true; -} - -/*! - Returns the y scale factor. - */ -qreal QGraphicsItem::yScale() const -{ - QGraphicsItemPrivate::TransformData *transformData = static_cast( - qVariantValue(d_ptr->extra(QGraphicsItemPrivate::ExtraTransform))); - if (!transformData) - return 1; - - return transformData->scaleY; -} - -/*! - Sets the y scale factor to \a factor. - */ -void QGraphicsItem::setYScale(qreal factor) -{ - QGraphicsItemPrivate::TransformData *transformData = static_cast( - qVariantValue(d_ptr->extra(QGraphicsItemPrivate::ExtraTransform))); - if (!transformData) { - if (factor == 1) - return; - transformData = new QGraphicsItemPrivate::TransformData; - d_ptr->setExtra(QGraphicsItemPrivate::ExtraTransform, qVariantFromValue(transformData)); - } - if (transformData->scaleY == factor) - return; - - prepareGeometryChange(); - - transformData->scaleY = factor; - transformData->dirty = true; - d_ptr->hasTransform = true; -} - -/*! - Returns the x rotation angle. - */ -qreal QGraphicsItem::xRotation() const -{ - QGraphicsItemPrivate::TransformData *transformData = static_cast( - qVariantValue(d_ptr->extra(QGraphicsItemPrivate::ExtraTransform))); - if (!transformData) - return 0; - return transformData->rotationX; -} - -/*! - Sets the x rotation angle to \a angle. - */ -void QGraphicsItem::setXRotation(qreal angle) -{ - QGraphicsItemPrivate::TransformData *transformData = static_cast( - qVariantValue(d_ptr->extra(QGraphicsItemPrivate::ExtraTransform))); - if (!transformData) { - if (qFuzzyCompare(angle + 1, 1)) - return; - transformData = new QGraphicsItemPrivate::TransformData; - d_ptr->setExtra(QGraphicsItemPrivate::ExtraTransform, qVariantFromValue(transformData)); - } - - prepareGeometryChange(); - - transformData->rotationX = angle; - - transformData->dirty = true; - d_ptr->hasTransform = true; -} - -/*! - Returns the y rotation angle. - */ -qreal QGraphicsItem::yRotation() const -{ - QGraphicsItemPrivate::TransformData *transformData = static_cast( - qVariantValue(d_ptr->extra(QGraphicsItemPrivate::ExtraTransform))); - if (!transformData) - return 0; - return transformData->rotationY; -} - -/*! - Sets the y rotation angle to \a angle. - */ -void QGraphicsItem::setYRotation(qreal angle) -{ - QGraphicsItemPrivate::TransformData *transformData = static_cast( - qVariantValue(d_ptr->extra(QGraphicsItemPrivate::ExtraTransform))); - if (!transformData) { - if (qFuzzyCompare(angle + 1, 1)) - return; - transformData = new QGraphicsItemPrivate::TransformData; - d_ptr->setExtra(QGraphicsItemPrivate::ExtraTransform, qVariantFromValue(transformData)); - } - - prepareGeometryChange(); - - transformData->rotationY = angle; - - transformData->dirty = true; - d_ptr->hasTransform = true; -} - -/*! - Returns the z rotation angle. - */ -qreal QGraphicsItem::zRotation() const -{ - QGraphicsItemPrivate::TransformData *transformData = static_cast( - qVariantValue(d_ptr->extra(QGraphicsItemPrivate::ExtraTransform))); - if (!transformData) - return 0; - return transformData->rotationZ; -} - -/*! - Sets the z rotation angle to \a angle. - */ -void QGraphicsItem::setZRotation(qreal angle) -{ - QGraphicsItemPrivate::TransformData *transformData = static_cast( - qVariantValue(d_ptr->extra(QGraphicsItemPrivate::ExtraTransform))); - if (!transformData) { - if (qFuzzyCompare(angle + 1, 1)) - return; - transformData = new QGraphicsItemPrivate::TransformData; - d_ptr->setExtra(QGraphicsItemPrivate::ExtraTransform, qVariantFromValue(transformData)); - } - - prepareGeometryChange(); - - transformData->rotationZ = angle; - - transformData->dirty = true; - d_ptr->hasTransform = true; -} - -/*! ->>>>>>> Remove scene transform cache from QGraphicsItem.:src/gui/graphicsview/qgraphicsitem.cpp This virtual function is called twice for all items by the QGraphicsScene::advance() slot. In the first phase, all items are called with \a phase == 0, indicating that items on the scene are about to diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index 9d5b58a..4deb6e5 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -347,7 +347,7 @@ public: quint32 dirtyClipPath : 1; quint32 emptyClipPath : 1; quint32 inSetPosHelper : 1; - quint32 unused : 3; + quint32 unused : 1; // New 32 bits quint32 flags : 11; -- cgit v0.12 From 0e650ed3a8e7e4bdf4c9d3eefd667d4abb318c5a Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Thu, 28 May 2009 15:31:46 +0200 Subject: simplify opacity handling in QGraphicsItem Greatly simplify how we handle opacity and store it as a member in QGraphicsItemPrivate. Remove the caching of effectiveOpacity. It's faster to calculate it on the fly, and the recursive painting algorithm will make even that need go away. Reviewed-by: Andreas --- src/gui/graphicsview/qgraphicsitem_p.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index 4deb6e5..aac1795 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -272,9 +272,7 @@ public: inline bool childrenCombineOpacity() const { - if (!children.size()) - return true; - if (flags & QGraphicsItem::ItemDoesntPropagateOpacityToChildren) + if (!children.size() || flags & QGraphicsItem::ItemDoesntPropagateOpacityToChildren) return false; for (int i = 0; i < children.size(); ++i) { @@ -347,7 +345,7 @@ public: quint32 dirtyClipPath : 1; quint32 emptyClipPath : 1; quint32 inSetPosHelper : 1; - quint32 unused : 1; + quint32 unused : 3; // New 32 bits quint32 flags : 11; -- cgit v0.12 From 910e3d807226027a48a3b02906ff8e15b662ad00 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Thu, 28 May 2009 16:08:25 +0200 Subject: smaller optimisation in setTransform --- src/gui/graphicsview/qgraphicsitem.cpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index 3008997..12aaba5 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -2881,10 +2881,7 @@ void QGraphicsItem::setMatrix(const QMatrix &matrix, bool combine) // Update and set the new transformation. prepareGeometryChange(); - if(!d_ptr->transform) - d_ptr->transform = new QTransform(newTransform); - else - *d_ptr->transform = newTransform; + *d_ptr->transform = newTransform; // Send post-notification. itemChange(ItemTransformHasChanged, newTransformVariant); @@ -2928,10 +2925,7 @@ void QGraphicsItem::setTransform(const QTransform &matrix, bool combine) // Update and set the new transformation. prepareGeometryChange(); - if(!d_ptr->transform) - d_ptr->transform = new QTransform(newTransform); - else - *d_ptr->transform = newTransform; + *d_ptr->transform = newTransform; // Send post-notification. itemChange(ItemTransformHasChanged, newTransformVariant); -- cgit v0.12 From f8f185b99a12e14374ce29501b8d13c5e3d125fd Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Thu, 28 May 2009 16:09:38 +0200 Subject: remove now unused flag --- src/gui/graphicsview/qgraphicsitem_p.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index aac1795..95a7733 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -348,11 +348,11 @@ public: quint32 unused : 3; // New 32 bits - quint32 flags : 11; + quint32 flags : 10; quint32 dirtyChildrenBoundingRect : 1; quint32 inDirtyList : 1; quint32 paintedViewBoundingRectsNeedRepaint : 1; - quint32 padding : 18; // feel free to use + quint32 padding : 19; // feel free to use // Optional stacking order int globalStackingOrder; -- cgit v0.12 From 6e92cbd42ce7e68112de8bce8a0468532843a947 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Thu, 28 May 2009 22:55:49 +0200 Subject: fix a small logic bug in childrenCombineOpacity Regression introduced during refactoring earlier today. --- src/gui/graphicsview/qgraphicsitem_p.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index 95a7733..acd2fcc 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -272,7 +272,9 @@ public: inline bool childrenCombineOpacity() const { - if (!children.size() || flags & QGraphicsItem::ItemDoesntPropagateOpacityToChildren) + if (!children.size()) + return true; + if (flags & QGraphicsItem::ItemDoesntPropagateOpacityToChildren) return false; for (int i = 0; i < children.size(); ++i) { -- cgit v0.12 From aba52a08d8868682e576d1b53d423cedb0a9134e Mon Sep 17 00:00:00 2001 From: Andreas Aardal Hanssen Date: Fri, 29 May 2009 08:54:31 +0200 Subject: Introduce QGraphicsItem::ItemHasNoContents. This flag helps optimize the case where an item is used only as a transformation node in a scene graph, and where the item itself doesn't paint anything. This is the default for FxItem (the subclasses that do paint enable the HasContents flag). This lets Graphics View know whether there's any point in setting up the world transform, opacity and other things. Reviewed-by: Lars --- src/gui/graphicsview/qgraphicsitem_p.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index acd2fcc..9d5b58a 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -350,11 +350,11 @@ public: quint32 unused : 3; // New 32 bits - quint32 flags : 10; + quint32 flags : 11; quint32 dirtyChildrenBoundingRect : 1; quint32 inDirtyList : 1; quint32 paintedViewBoundingRectsNeedRepaint : 1; - quint32 padding : 19; // feel free to use + quint32 padding : 18; // feel free to use // Optional stacking order int globalStackingOrder; -- cgit v0.12 From 32c09e7a36ecd41e8beb2a1f947944502793fd84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Nilsen?= Date: Thu, 28 May 2009 20:16:20 +0200 Subject: More re-factoring of Graphics View's update mechanism. This time with a recursive approach of processing dirty items. I've kept the previous approach using a dirty list, but the recursive one is now the default. Use QT_GV_USE_DIRTY_LIST=1 to swap. I've also cached the item's device transform in both cases so that we can re-use it later when drawing the item. --- src/gui/graphicsview/qgraphicsitem.cpp | 2 +- src/gui/graphicsview/qgraphicsitem_p.h | 21 ++- src/gui/graphicsview/qgraphicsscene.cpp | 241 +++++++++++++++++++++++--------- src/gui/graphicsview/qgraphicsscene_p.h | 4 + 4 files changed, 185 insertions(+), 83 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index 12aaba5..c3744b2 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -3769,7 +3769,7 @@ bool QGraphicsItemPrivate::discardUpdateRequest(bool ignoreClipping, bool ignore // 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. return (!visible && !ignoreVisibleBit) - || (!ignoreDirtyBit && (dirty || hasDirtyAncestor())) + || (!ignoreDirtyBit && dirty) || !scene || (scene->d_func()->updateAll && scene->d_func()->hasSceneRect) || (!ignoreClipping && (childrenClippedToShape() && isClippedAway())) diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index 9d5b58a..deaf30f 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -145,6 +145,9 @@ public: dirtyChildrenBoundingRect(1), inDirtyList(0), paintedViewBoundingRectsNeedRepaint(0), + allChildrenDirty(0), + fullUpdatePending(0), + hasValidDeviceTransform(0), globalStackingOrder(-1), q_ptr(0) { @@ -297,18 +300,6 @@ public: || (childrenCombineOpacity() && isFullyTransparent()); } - inline bool hasDirtyAncestor() const - { - QGraphicsItem *p = parent; - while (p) { - if (p->d_ptr->dirtyChildren || (p->d_ptr->dirty && p->d_ptr->childrenClippedToShape())) - return true; - p = p->d_ptr->parent; - } - return false; - } - - QPainterPath cachedClipPath; QRectF childrenBoundingRect; QRectF needsRepaint; @@ -320,6 +311,7 @@ public: QGraphicsItem *parent; QList children; QTransform *transform; + QTransform deviceTransform; int siblingIndex; int index; int depth; @@ -354,7 +346,10 @@ public: quint32 dirtyChildrenBoundingRect : 1; quint32 inDirtyList : 1; quint32 paintedViewBoundingRectsNeedRepaint : 1; - quint32 padding : 18; // feel free to use + quint32 allChildrenDirty : 1; + quint32 fullUpdatePending : 1; + quint32 hasValidDeviceTransform : 1; + quint32 padding : 15; // feel free to use // Optional stacking order int globalStackingOrder; diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index eaebd1a..a5ac9d9 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -337,6 +337,7 @@ QGraphicsScenePrivate::QGraphicsScenePrivate() hasSceneRect(false), updateAll(false), calledEmitUpdated(false), + processDirtyItemsEmitted(false), selectionChanging(0), regenerateIndex(true), purgePending(false), @@ -683,73 +684,70 @@ void QGraphicsScenePrivate::_q_polishItems() void QGraphicsScenePrivate::_q_processDirtyItems() { - Q_Q(QGraphicsScene); - if (dirtyItems.isEmpty()) - return; + static int useDirtyListEnv = qgetenv("QT_GV_USE_DIRTY_LIST").toInt(); + processDirtyItemsEmitted = false; if (updateAll) { - for (int i = 0; i < dirtyItems.size(); ++i) - resetDirtyItem(dirtyItems.at(i)); - dirtyItems.clear(); + if (useDirtyListEnv) { + for (int i = 0; i < dirtyItems.size(); ++i) + resetDirtyItem(dirtyItems.at(i)); + dirtyItems.clear(); + } + return; + } + + if (!useDirtyListEnv) { + processDirtyItemsRecursive(0, views.at(0)->viewportTransform()); + for (int i = 0; i < views.size(); ++i) + views.at(i)->d_func()->processPendingUpdates(); return; } - const bool useCompatUpdate = views.isEmpty() || (connectedSignals & changedSignalMask); for (int i = 0; i < dirtyItems.size(); ++i) { QGraphicsItem *item = dirtyItems.at(i); - if (useCompatUpdate && !item->d_ptr->itemIsUntransformable() - && qFuzzyIsNull(item->boundingRegionGranularity())) { - // This block of code is kept for compatibility. Since 4.5, by default - // QGraphicsView does not connect the signal and we use the below - // method of delivering updates. - q->update(item->sceneBoundingRect()); - resetDirtyItem(item); - continue; + QGraphicsView *view = views.at(0); + QGraphicsViewPrivate *viewPrivate = view->d_func(); + const QTransform deviceTransform = item->deviceTransform(view->viewportTransform()); + + QRectF dirtyRect = adjustedItemBoundingRect(item); + if (!item->d_ptr->fullUpdatePending) { + _q_adjustRect(&item->d_ptr->needsRepaint); + dirtyRect &= item->d_ptr->needsRepaint; } - QRectF dirtyRect; - bool uninitializedDirtyRect = true; - - for (int j = 0; j < views.size(); ++j) { - QGraphicsView *view = views.at(j); - QGraphicsViewPrivate *viewPrivate = view->d_func(); - if (viewPrivate->fullUpdatePending) - continue; - switch (viewPrivate->viewportUpdateMode) { - case QGraphicsView::NoViewportUpdate: - continue; - case QGraphicsView::FullViewportUpdate: - view->viewport()->update(); - viewPrivate->fullUpdatePending = 1; - continue; - default: - break; - } - - if (uninitializedDirtyRect) { - dirtyRect = adjustedItemBoundingRect(item); - if (!item->d_ptr->dirty) { - _q_adjustRect(&item->d_ptr->needsRepaint); - dirtyRect &= item->d_ptr->needsRepaint; - } - - if (item->d_ptr->dirtyChildren && !item->d_ptr->children.isEmpty() - && !item->d_ptr->childrenClippedToShape()) { - QRectF childrenBounds = item->childrenBoundingRect(); - _q_adjustRect(&childrenBounds); - dirtyRect |= childrenBounds; - } - uninitializedDirtyRect = false; - } + if (item->d_ptr->allChildrenDirty && !item->d_ptr->children.isEmpty() + && !item->d_ptr->childrenClippedToShape()) { + QRectF childrenBounds = item->childrenBoundingRect(); + _q_adjustRect(&childrenBounds); + dirtyRect |= childrenBounds; + } - if (item->d_ptr->paintedViewBoundingRectsNeedRepaint) - viewPrivate->updateRect(item->d_ptr->paintedViewBoundingRects.value(viewPrivate->viewport)); + if (item->d_ptr->paintedViewBoundingRectsNeedRepaint) + viewPrivate->updateRect(item->d_ptr->paintedViewBoundingRects.value(viewPrivate->viewport)); - if (!item->d_ptr->hasBoundingRegionGranularity) - viewPrivate->updateRect(viewPrivate->mapToViewRect(item, dirtyRect)); + bool dirtyRectOutsideViewport = false; + if (item->d_ptr->hasBoundingRegionGranularity) { + const QRegion dirtyViewRegion = deviceTransform.map(QRegion(dirtyRect.toRect())) + & viewPrivate->viewport->rect(); + if (!dirtyViewRegion.isEmpty()) + viewPrivate->updateRegion(dirtyViewRegion); else - viewPrivate->updateRegion(viewPrivate->mapToViewRegion(item, dirtyRect)); + dirtyRectOutsideViewport = true; + } else { + const QRect dirtyViewRect = deviceTransform.mapRect(dirtyRect).toRect() + & viewPrivate->viewport->rect(); + if (!dirtyViewRect.isEmpty()) + viewPrivate->updateRect(dirtyViewRect); + else + dirtyRectOutsideViewport = true; + } + if (!dirtyRectOutsideViewport) { + // We know for sure this item will be process in the paint event, hence + // store its device transform and re-use it when drawing. + item->d_ptr->hasValidDeviceTransform = 1; + item->d_ptr->deviceTransform = deviceTransform; } + resetDirtyItem(item); } @@ -5064,6 +5062,7 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * QTransform transform; QRect viewBoundingRect; if (item) { + if (!item->d_ptr->hasValidDeviceTransform) { if (item->d_ptr->itemIsUntransformable()) { transform = item->deviceTransform(viewTransform); } else { @@ -5082,6 +5081,10 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * transform = parentTransform; } } + } else { + transform = item->d_ptr->deviceTransform; + item->d_ptr->hasValidDeviceTransform = 0; + } QRectF brect = item->boundingRect(); if (!brect.size().isNull()) { // ### This does not take the clip into account. @@ -5176,25 +5179,120 @@ void QGraphicsScenePrivate::markDirty(QGraphicsItem *item, const QRectF &rect, b if (!fullItemUpdate && rect.isEmpty()) return; - if (dirtyItems.isEmpty()) + if (!processDirtyItemsEmitted) { QMetaObject::invokeMethod(q_ptr, "_q_processDirtyItems", Qt::QueuedConnection); + processDirtyItemsEmitted = true; + } + + item->d_ptr->dirty = 1; + if (fullItemUpdate) + item->d_ptr->fullUpdatePending = 1; + else if (!item->d_ptr->fullUpdatePending) + item->d_ptr->needsRepaint |= rect; - if (item->d_ptr->inDirtyList) { - if (fullItemUpdate) - item->d_ptr->dirty = 1; - else if (!item->d_ptr->dirty) - item->d_ptr->needsRepaint |= rect; + if (invalidateChildren) { + item->d_ptr->allChildrenDirty = 1; + item->d_ptr->dirtyChildren = 1; + } + + static int useDirtyListEnv = qgetenv("QT_GV_USE_DIRTY_LIST").toInt(); + if (useDirtyListEnv) { + if (!item->d_ptr->inDirtyList) { + dirtyItems.append(item); + item->d_ptr->inDirtyList = 1; + } } else { - dirtyItems.append(item); - item->d_ptr->inDirtyList = 1; - if (fullItemUpdate) - item->d_ptr->dirty = 1; - else if (!item->d_ptr->dirty) - item->d_ptr->needsRepaint = rect; + QGraphicsItem *p = item->d_ptr->parent; + while (p && !p->d_ptr->dirtyChildren) { + p->d_ptr->dirtyChildren = 1; + p = p->d_ptr->parent; + } } +} - if (invalidateChildren) - item->d_ptr->dirtyChildren = 1; +void QGraphicsScenePrivate::processDirtyItemsRecursive(QGraphicsItem *item, const QTransform &parentTransform) +{ + Q_ASSERT(!item || item->d_ptr->dirty || item->d_ptr->dirtyChildren); + + // Calculate the full transform for this item. + QTransform transform; + if (item) { + if (item->d_ptr->itemIsUntransformable()) { + transform = item->deviceTransform(views.at(0)->viewportTransform()); + } else { + const QPointF &pos = item->d_ptr->pos; + bool posNull = pos.isNull(); + if (!posNull || item->d_ptr->transform) { + if (item->d_ptr->transform) { + transform = *item->d_ptr->transform; + if (!posNull) + transform *= QTransform::fromTranslate(pos.x(), pos.y()); + transform *= parentTransform; + } else { + transform = QTransform::fromTranslate(pos.x(), pos.y()) * parentTransform; + } + } else { + transform = parentTransform; + } + } + } else { + transform = parentTransform; + } + + // Process item. + if (item && item->d_ptr->dirty) { + QRectF dirtyRect = adjustedItemBoundingRect(item); + if (!item->d_ptr->fullUpdatePending) { + _q_adjustRect(&item->d_ptr->needsRepaint); + dirtyRect &= item->d_ptr->needsRepaint; + } + + QGraphicsViewPrivate *viewPrivate = views.at(0)->d_func(); + if (item->d_ptr->paintedViewBoundingRectsNeedRepaint) + viewPrivate->updateRect(item->d_ptr->paintedViewBoundingRects.value(viewPrivate->viewport)); + + bool dirtyRectOutsideViewport = false; + if (item->d_ptr->hasBoundingRegionGranularity) { + const QRegion dirtyViewRegion = transform.map(QRegion(dirtyRect.toRect())) + & viewPrivate->viewport->rect(); + if (!dirtyViewRegion.isEmpty()) + viewPrivate->updateRegion(dirtyViewRegion); + else + dirtyRectOutsideViewport = true; + } else { + const QRect dirtyViewRect = transform.mapRect(dirtyRect).toRect() + & viewPrivate->viewport->rect(); + if (!dirtyViewRect.isEmpty()) + viewPrivate->updateRect(dirtyViewRect); + else + dirtyRectOutsideViewport = true; + } + if (!dirtyRectOutsideViewport) { + // We know for sure this item will be process in the paint event, hence + // store its device transform and re-use it when drawing. + item->d_ptr->hasValidDeviceTransform = 1; + item->d_ptr->deviceTransform = transform; + } + } + + // Process root items / children. + if (!item || item->d_ptr->dirtyChildren) { + QList *children = item ? &item->d_ptr->children : &topLevelItems; + const bool allChildrenDirty = item && item->d_ptr->allChildrenDirty; + for (int i = 0; i < children->size(); ++i) { + QGraphicsItem *child = children->at(i); + if (allChildrenDirty) { + child->d_ptr->dirty = 1; + } else if (!child->d_ptr->dirty && !child->d_ptr->dirtyChildren) { + resetDirtyItem(child); + continue; + } + processDirtyItemsRecursive(child, transform); + } + } + + if (item) + resetDirtyItem(item); } /*! @@ -5302,7 +5400,12 @@ void QGraphicsScene::drawItems(QPainter *painter, } // Set up the painter transform - painter->setWorldTransform(item->deviceTransform(viewTransform), false); + if (item->d_ptr->hasValidDeviceTransform) { + painter->setWorldTransform(item->d_ptr->deviceTransform); + item->d_ptr->hasValidDeviceTransform = 0; + } else { + painter->setWorldTransform(item->deviceTransform(viewTransform), false); + } // Save painter bool saveState = (d->painterStateProtection || (item->flags() & QGraphicsItem::ItemClipsToShape)); diff --git a/src/gui/graphicsview/qgraphicsscene_p.h b/src/gui/graphicsview/qgraphicsscene_p.h index bf7ac0a..50c716c 100644 --- a/src/gui/graphicsview/qgraphicsscene_p.h +++ b/src/gui/graphicsview/qgraphicsscene_p.h @@ -105,6 +105,7 @@ public: QList updatedRects; bool updateAll; bool calledEmitUpdated; + bool processDirtyItemsEmitted; QPainterPath selectionArea; int selectionChanging; @@ -257,6 +258,7 @@ public: const QRegion &exposedRegion, QWidget *widget, QGraphicsView::OptimizationFlags optimizationFlags); void markDirty(QGraphicsItem *item, const QRectF &rect = QRectF(), bool invalidateChildren = false, bool maybeDirtyClipPath = false, bool force = false, bool ignoreOpacity = false); + void processDirtyItemsRecursive(QGraphicsItem *item, const QTransform &); inline void resetDirtyItem(QGraphicsItem *item) { @@ -266,6 +268,8 @@ public: item->d_ptr->dirtyChildren = 0; item->d_ptr->inDirtyList = 0; item->d_ptr->needsRepaint = QRectF(); + item->d_ptr->allChildrenDirty = 0; + item->d_ptr->fullUpdatePending = 0; } inline void removeFromDirtyItems(QGraphicsItem *item) -- cgit v0.12 From f582ed67c29e2406adeb0a52c7a68a51e0c2e8ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Nilsen?= Date: Fri, 29 May 2009 13:20:42 +0200 Subject: Only call qgetenv("QGRAPHICSVIEW_DIRECT") once. --- src/gui/graphicsview/qgraphicsview.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp index 68c0e39..369301e 100644 --- a/src/gui/graphicsview/qgraphicsview.cpp +++ b/src/gui/graphicsview/qgraphicsview.cpp @@ -3313,9 +3313,8 @@ void QGraphicsView::paintEvent(QPaintEvent *event) int backgroundTime = stopWatch.elapsed() - exposedTime; #endif - const char *directEnv = getenv("QGRAPHICSVIEW_DIRECT"); - bool overrideDirectPaint = directEnv && atoi(directEnv) != 0; - if (overrideDirectPaint || (d->optimizationFlags & BypassDrawItems)) { + static int directEnv = getenv("QGRAPHICSVIEW_DIRECT").toInt(); + if (directEnv || (d->optimizationFlags & BypassDrawItems)) { d->scene->d_func()->drawSubtreeRecursive(0, &painter, viewTransform, viewTransform, exposedRegion, viewport(), d->optimizationFlags); } else { -- cgit v0.12 From 669679d389ff0585bad30d41b085a4189d0e7a91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Nilsen?= Date: Fri, 29 May 2009 13:24:02 +0200 Subject: Ooops. Compile :) --- src/gui/graphicsview/qgraphicsview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp index 369301e..354feae 100644 --- a/src/gui/graphicsview/qgraphicsview.cpp +++ b/src/gui/graphicsview/qgraphicsview.cpp @@ -3313,7 +3313,7 @@ void QGraphicsView::paintEvent(QPaintEvent *event) int backgroundTime = stopWatch.elapsed() - exposedTime; #endif - static int directEnv = getenv("QGRAPHICSVIEW_DIRECT").toInt(); + static int directEnv = qgetenv("QGRAPHICSVIEW_DIRECT").toInt(); if (directEnv || (d->optimizationFlags & BypassDrawItems)) { d->scene->d_func()->drawSubtreeRecursive(0, &painter, viewTransform, viewTransform, exposedRegion, viewport(), d->optimizationFlags); -- cgit v0.12 From a10e4b983e228284202df536846e6b6d4a8cf40e Mon Sep 17 00:00:00 2001 From: Andreas Aardal Hanssen Date: Fri, 29 May 2009 14:40:32 +0200 Subject: Simplify the QTransform calculations. --- src/gui/graphicsview/qgraphicsscene.cpp | 46 ++++++++------------------------- 1 file changed, 11 insertions(+), 35 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index a5ac9d9..434cc8e 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -5059,28 +5059,18 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * return; // Calculate the full transform for this item. - QTransform transform; + QTransform transform = parentTransform; QRect viewBoundingRect; if (item) { if (!item->d_ptr->hasValidDeviceTransform) { - if (item->d_ptr->itemIsUntransformable()) { - transform = item->deviceTransform(viewTransform); - } else { - const QPointF &pos = item->d_ptr->pos; - bool posNull = pos.isNull(); - if (!posNull || item->d_ptr->transform) { - if (item->d_ptr->transform) { - QTransform x = *item->d_ptr->transform; - if (!posNull) - x *= QTransform::fromTranslate(pos.x(), pos.y()); - transform = x * parentTransform; - } else { - transform = QTransform::fromTranslate(pos.x(), pos.y()) * parentTransform; - } + if (item->d_ptr->itemIsUntransformable()) { + transform = item->deviceTransform(viewTransform); } else { - transform = parentTransform; + const QPointF &pos = item->d_ptr->pos; + transform.translate(pos.x(), pos.y()); + if (item->d_ptr->transform) + transform = *item->d_ptr->transform * transform; } - } } else { transform = item->d_ptr->deviceTransform; item->d_ptr->hasValidDeviceTransform = 0; @@ -5093,8 +5083,6 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * item->d_ptr->paintedViewBoundingRects.insert(widget, paintedViewBoundingRect); viewBoundingRect = paintedViewBoundingRect & exposedRegion.boundingRect(); } - } else { - transform = parentTransform; } bool childClip = (item && (item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape)); @@ -5215,28 +5203,16 @@ void QGraphicsScenePrivate::processDirtyItemsRecursive(QGraphicsItem *item, cons Q_ASSERT(!item || item->d_ptr->dirty || item->d_ptr->dirtyChildren); // Calculate the full transform for this item. - QTransform transform; + QTransform transform = parentTransform; if (item) { if (item->d_ptr->itemIsUntransformable()) { transform = item->deviceTransform(views.at(0)->viewportTransform()); } else { const QPointF &pos = item->d_ptr->pos; - bool posNull = pos.isNull(); - if (!posNull || item->d_ptr->transform) { - if (item->d_ptr->transform) { - transform = *item->d_ptr->transform; - if (!posNull) - transform *= QTransform::fromTranslate(pos.x(), pos.y()); - transform *= parentTransform; - } else { - transform = QTransform::fromTranslate(pos.x(), pos.y()) * parentTransform; - } - } else { - transform = parentTransform; - } + transform.translate(pos.x(), pos.y()); + if (item->d_ptr->transform) + transform = *item->d_ptr->transform * transform; } - } else { - transform = parentTransform; } // Process item. -- cgit v0.12 From 2581606e0f86280546c498fec130d2625376dda7 Mon Sep 17 00:00:00 2001 From: Andreas Aardal Hanssen Date: Fri, 29 May 2009 15:10:44 +0200 Subject: Remove siblingIndex and use stable sorting instead. To avoid sorting siblings in real-time, ensure we lazily sort the list in place when needed. Reviewed-by: bnilsen --- src/gui/graphicsview/qgraphicsitem.cpp | 18 ++++++------------ src/gui/graphicsview/qgraphicsitem_p.h | 6 +++--- src/gui/graphicsview/qgraphicsscene.cpp | 27 ++++++++++++++------------- src/gui/graphicsview/qgraphicsscene_p.h | 1 + 4 files changed, 24 insertions(+), 28 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index c3744b2..9159381 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -1997,15 +1997,16 @@ qreal QGraphicsItem::effectiveOpacity() const if (!d_ptr->parent) return d_ptr->opacity; - QGraphicsItem::GraphicsItemFlags myFlags = flags(); - QGraphicsItem::GraphicsItemFlags parentFlags = d_ptr->parent ? d_ptr->parent->flags() : QGraphicsItem::GraphicsItemFlags(0); + int myFlags = d_ptr->flags; + int parentFlags = d_ptr->parent ? d_ptr->parent->d_ptr->flags : 0; // If I have a parent, and I don't ignore my parent's opacity, and my // parent propagates to me, then combine my local opacity with my parent's // effective opacity into my effective opacity. if (!(myFlags & QGraphicsItem::ItemIgnoresParentOpacity) - && !(parentFlags & QGraphicsItem::ItemDoesntPropagateOpacityToChildren)) + && !(parentFlags & QGraphicsItem::ItemDoesntPropagateOpacityToChildren)) { return d_ptr->opacity * d_ptr->parent->effectiveOpacity(); + } return d_ptr->opacity; } @@ -3793,7 +3794,7 @@ void QGraphicsItemPrivate::resolveDepth(int parentDepth) */ void QGraphicsItemPrivate::addChild(QGraphicsItem *child) { - child->d_ptr->siblingIndex = children.size(); + needSortChildren = 1; children.append(child); } @@ -3802,14 +3803,7 @@ void QGraphicsItemPrivate::addChild(QGraphicsItem *child) */ void QGraphicsItemPrivate::removeChild(QGraphicsItem *child) { - int idx = child->d_ptr->siblingIndex; - int size = children.size(); - for (int i = idx; i < size - 1; ++i) { - QGraphicsItem *p = children[i + 1]; - children[i] = p; - p->d_ptr->siblingIndex = i; - } - children.removeLast(); + children.removeOne(child); } /*! diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index deaf30f..80b1fb4 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -116,7 +116,6 @@ public: scene(0), parent(0), transform(0), - siblingIndex(-1), index(-1), depth(0), acceptedMouseButtons(0x1f), @@ -141,6 +140,7 @@ public: dirtyClipPath(1), emptyClipPath(0), inSetPosHelper(0), + needSortChildren(1), flags(0), dirtyChildrenBoundingRect(1), inDirtyList(0), @@ -312,7 +312,6 @@ public: QList children; QTransform *transform; QTransform deviceTransform; - int siblingIndex; int index; int depth; @@ -339,7 +338,8 @@ public: quint32 dirtyClipPath : 1; quint32 emptyClipPath : 1; quint32 inSetPosHelper : 1; - quint32 unused : 3; + quint32 needSortChildren : 1; + quint32 unused : 2; // New 32 bits quint32 flags : 11; diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index 434cc8e..52dc152 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -339,6 +339,7 @@ QGraphicsScenePrivate::QGraphicsScenePrivate() calledEmitUpdated(false), processDirtyItemsEmitted(false), selectionChanging(0), + needSortTopLevelItems(true), regenerateIndex(true), purgePending(false), indexTimerId(0), @@ -631,7 +632,7 @@ void QGraphicsScenePrivate::_q_emitUpdated() */ void QGraphicsScenePrivate::registerTopLevelItem(QGraphicsItem *item) { - item->d_ptr->siblingIndex = topLevelItems.size(); + needSortTopLevelItems = true; topLevelItems.append(item); } @@ -640,14 +641,7 @@ void QGraphicsScenePrivate::registerTopLevelItem(QGraphicsItem *item) */ void QGraphicsScenePrivate::unregisterTopLevelItem(QGraphicsItem *item) { - int idx = item->d_ptr->siblingIndex; - int size = topLevelItems.size(); - for (int i = idx; i < size - 1; ++i) { - QGraphicsItem *p = topLevelItems[i + 1]; - topLevelItems[i] = p; - p->d_ptr->siblingIndex = i; - } - topLevelItems.removeLast(); + topLevelItems.removeOne(item); } /*! @@ -1910,7 +1904,7 @@ inline bool qt_closestLeaf(const QGraphicsItem *item1, const QGraphicsItem *item if (f1 != f2) return f2; qreal z1 = d1->z; qreal z2 = d2->z; - return z1 != z2 ? z1 > z2 : d1->siblingIndex > d2->siblingIndex; + return z1 > z2; } static inline bool qt_notclosestLeaf(const QGraphicsItem *item1, const QGraphicsItem *item2) @@ -5100,9 +5094,16 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * } // Find and sort children. - QList children = item ? item->d_ptr->children : topLevelItems; - if (!dontDrawChildren) - qSort(children.begin(), children.end(), qt_notclosestLeaf); + QList &children = item ? item->d_ptr->children : topLevelItems; + if (!dontDrawChildren) { + if (item && item->d_ptr->needSortChildren) { + item->d_ptr->needSortChildren = 0; + qStableSort(children.begin(), children.end(), qt_notclosestLeaf); + } else if (!item && needSortTopLevelItems) { + needSortTopLevelItems = false; + qStableSort(children.begin(), children.end(), qt_notclosestLeaf); + } + } // Draw children behind int i; diff --git a/src/gui/graphicsview/qgraphicsscene_p.h b/src/gui/graphicsview/qgraphicsscene_p.h index 50c716c..e7e96f5 100644 --- a/src/gui/graphicsview/qgraphicsscene_p.h +++ b/src/gui/graphicsview/qgraphicsscene_p.h @@ -116,6 +116,7 @@ public: QList pendingUpdateItems; QList unpolishedItems; QList topLevelItems; + bool needSortTopLevelItems; QMap movingItemsInitialPositions; void registerTopLevelItem(QGraphicsItem *item); void unregisterTopLevelItem(QGraphicsItem *item); -- cgit v0.12 From 5d54c09085979431831297f0e63f39c73f884d20 Mon Sep 17 00:00:00 2001 From: Andreas Aardal Hanssen Date: Fri, 29 May 2009 15:32:38 +0200 Subject: Avoid calling QGraphicsItem::effectiveOpacity() when rendering - instead just calculate it top-down. Reviewed-by: bnilsen --- src/gui/graphicsview/qgraphicsscene.cpp | 30 ++++++++++++++++++++++++------ src/gui/graphicsview/qgraphicsscene_p.h | 3 ++- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index 52dc152..1d33361 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -5047,10 +5047,27 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter *painter, const QTransform &parentTransform, const QTransform &viewTransform, const QRegion &exposedRegion, QWidget *widget, - QGraphicsView::OptimizationFlags optimizationFlags) + QGraphicsView::OptimizationFlags optimizationFlags, + qreal parentOpacity) { - if (item && item->d_ptr->isInvisible()) - return; + // Calculate opacity. + qreal opacity; + if (item) { + if (!item->d_ptr->visible) + return; + QGraphicsItem *p = item->d_ptr->parent; + bool itemIgnoresParentOpacity = item->d_ptr->flags & QGraphicsItem::ItemIgnoresParentOpacity; + bool parentDoesntPropagateOpacity = (p && (p->d_ptr->flags & QGraphicsItem::ItemDoesntPropagateOpacityToChildren)); + if (!itemIgnoresParentOpacity && !parentDoesntPropagateOpacity) { + opacity = parentOpacity * item->opacity(); + } else { + opacity = item->d_ptr->opacity; + } + if (opacity == 0.0 && !(item->d_ptr->flags & QGraphicsItem::ItemDoesntPropagateOpacityToChildren)) + return; + } else { + opacity = parentOpacity; + } // Calculate the full transform for this item. QTransform transform = parentTransform; @@ -5113,7 +5130,8 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * if (!(child->d_ptr->flags & QGraphicsItem::ItemStacksBehindParent)) break; drawSubtreeRecursive(child, painter, transform, viewTransform, - exposedRegion, widget, optimizationFlags); + exposedRegion, widget, optimizationFlags, + opacity); } } @@ -5130,7 +5148,7 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * painter->setWorldTransform(transform); if (clipsToShape) painter->setClipPath(item->shape(), Qt::IntersectClip); - painter->setOpacity(item->effectiveOpacity()); + painter->setOpacity(opacity); drawItemHelper(item, painter, &option, widget, false); @@ -5142,7 +5160,7 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * if (!dontDrawChildren) { for (; i < children.size(); ++i) { drawSubtreeRecursive(children.at(i), painter, transform, viewTransform, - exposedRegion, widget, optimizationFlags); + exposedRegion, widget, optimizationFlags, opacity); } } diff --git a/src/gui/graphicsview/qgraphicsscene_p.h b/src/gui/graphicsview/qgraphicsscene_p.h index e7e96f5..4facec3 100644 --- a/src/gui/graphicsview/qgraphicsscene_p.h +++ b/src/gui/graphicsview/qgraphicsscene_p.h @@ -256,7 +256,8 @@ public: void drawSubtreeRecursive(QGraphicsItem *item, QPainter *painter, const QTransform &parentTransform, const QTransform &viewTransform, - const QRegion &exposedRegion, QWidget *widget, QGraphicsView::OptimizationFlags optimizationFlags); + const QRegion &exposedRegion, QWidget *widget, QGraphicsView::OptimizationFlags optimizationFlags, + qreal parentOpacity = qreal(1.0)); void markDirty(QGraphicsItem *item, const QRectF &rect = QRectF(), bool invalidateChildren = false, bool maybeDirtyClipPath = false, bool force = false, bool ignoreOpacity = false); void processDirtyItemsRecursive(QGraphicsItem *item, const QTransform &); -- cgit v0.12 From e5ffaeb4bc9b76a96fdddb31460d4acdc564ae3c Mon Sep 17 00:00:00 2001 From: Andreas Aardal Hanssen Date: Fri, 29 May 2009 16:04:59 +0200 Subject: Experimental change - disable itemChange notifications for move and transform. This change is only to test how much of an impact the itemChange mechanism has on performance. It's easy to revert later on. --- src/gui/graphicsview/qgraphicsitem.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index 9159381..0b06613 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -39,6 +39,8 @@ ** ****************************************************************************/ +#define QGRAPHICSITEM_NO_ITEMCHANGE + /*! \class QGraphicsItem \brief The QGraphicsItem class is the base class for all graphical @@ -2036,8 +2038,12 @@ qreal QGraphicsItem::effectiveOpacity() const void QGraphicsItem::setOpacity(qreal opacity) { // Notify change. +#ifndef QGRAPHICSITEM_NO_ITEMCHANGE const QVariant newOpacityVariant(itemChange(ItemOpacityChange, double(opacity))); qreal newOpacity = newOpacityVariant.toDouble(); +#else + qreal newOpacity = opacity; +#endif // Normalize. newOpacity = qBound(0.0, newOpacity, 1.0); @@ -2049,7 +2055,9 @@ void QGraphicsItem::setOpacity(qreal opacity) d_ptr->opacity = newOpacity; // Notify change. +#ifndef QGRAPHICSITEM_NO_ITEMCHANGE itemChange(ItemOpacityHasChanged, newOpacity); +#endif // Update. if (d_ptr->scene) @@ -2499,10 +2507,14 @@ void QGraphicsItemPrivate::setPosHelper(const QPointF &pos) return; // Notify the item that the position is changing. +#ifndef QGRAPHICSITEM_NO_ITEMCHANGE const QVariant newPosVariant(q->itemChange(QGraphicsItem::ItemPositionChange, pos)); QPointF newPos = newPosVariant.toPointF(); if (newPos == this->pos) return; +#else + QPointF newPos = pos; +#endif // Update and repositition. inSetPosHelper = 1; @@ -2512,7 +2524,9 @@ void QGraphicsItemPrivate::setPosHelper(const QPointF &pos) this->pos = newPos; // Send post-notification. +#ifndef QGRAPHICSITEM_NO_ITEMCHANGE q->itemChange(QGraphicsItem::ItemPositionHasChanged, newPosVariant); +#endif inSetPosHelper = 0; } @@ -2874,18 +2888,22 @@ void QGraphicsItem::setMatrix(const QMatrix &matrix, bool combine) return; // Notify the item that the transformation matrix is changing. +#ifndef QGRAPHICSITEM_NO_ITEMCHANGE const QVariant newTransformVariant(itemChange(ItemTransformChange, qVariantFromValue(newTransform))); newTransform = qVariantValue(newTransformVariant); if (*d_ptr->transform == newTransform) return; +#endif // Update and set the new transformation. prepareGeometryChange(); *d_ptr->transform = newTransform; // Send post-notification. +#ifndef QGRAPHICSITEM_NO_ITEMCHANGE itemChange(ItemTransformHasChanged, newTransformVariant); +#endif } /*! -- cgit v0.12 From d705abe962e309318ecad45064cbf61a2ffc79e2 Mon Sep 17 00:00:00 2001 From: Andreas Aardal Hanssen Date: Fri, 29 May 2009 16:05:55 +0200 Subject: Experimental change: replace all updates with repaints. This seems to be the only way to get a high frame rate, regardless of the performance of painting and all. --- src/gui/graphicsview/qgraphicsview.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp index 354feae..e205985 100644 --- a/src/gui/graphicsview/qgraphicsview.cpp +++ b/src/gui/graphicsview/qgraphicsview.cpp @@ -815,11 +815,11 @@ void QGraphicsViewPrivate::processPendingUpdates() if (viewportUpdateMode == QGraphicsView::BoundingRectViewportUpdate) { if (optimizationFlags & QGraphicsView::DontAdjustForAntialiasing) - viewport->update(dirtyBoundingRect); + viewport->repaint(dirtyBoundingRect); else - viewport->update(dirtyBoundingRect.adjusted(-2, -2, 2, 2)); + viewport->repaint(dirtyBoundingRect.adjusted(-2, -2, 2, 2)); } else { - viewport->update(dirtyRegion); // Already adjusted in updateRect/Region. + viewport->repaint(dirtyRegion); // Already adjusted in updateRect/Region. } dirtyBoundingRect = QRect(); @@ -829,7 +829,7 @@ void QGraphicsViewPrivate::processPendingUpdates() void QGraphicsViewPrivate::updateAll() { Q_Q(QGraphicsView); - q->viewport()->update(); + q->viewport()->repaint(); fullUpdatePending = true; dirtyBoundingRect = QRect(); dirtyRegion = QRegion(); @@ -846,13 +846,13 @@ void QGraphicsViewPrivate::updateRegion(const QRegion &r) switch (viewportUpdateMode) { case QGraphicsView::FullViewportUpdate: fullUpdatePending = true; - q->viewport()->update(); + q->viewport()->repaint(); break; case QGraphicsView::BoundingRectViewportUpdate: dirtyBoundingRect |= r.boundingRect(); if (dirtyBoundingRect.contains(q->viewport()->rect())) { fullUpdatePending = true; - q->viewport()->update(); + q->viewport()->repaint(); } break; case QGraphicsView::SmartViewportUpdate: // ### DEPRECATE @@ -882,13 +882,13 @@ void QGraphicsViewPrivate::updateRect(const QRect &r) switch (viewportUpdateMode) { case QGraphicsView::FullViewportUpdate: fullUpdatePending = true; - q->viewport()->update(); + q->viewport()->repaint(); break; case QGraphicsView::BoundingRectViewportUpdate: dirtyBoundingRect |= r; if (dirtyBoundingRect.contains(q->viewport()->rect())) { fullUpdatePending = true; - q->viewport()->update(); + q->viewport()->repaint(); } break; case QGraphicsView::SmartViewportUpdate: // ### DEPRECATE -- cgit v0.12 From c714b0e5527377bf3189b15a3bea0063f8aecebf Mon Sep 17 00:00:00 2001 From: Andreas Aardal Hanssen Date: Fri, 29 May 2009 16:47:08 +0200 Subject: Avoid recursive repaint by calling update() when there's a full scene update. --- src/gui/graphicsview/qgraphicsview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp index e205985..7f6fd5e 100644 --- a/src/gui/graphicsview/qgraphicsview.cpp +++ b/src/gui/graphicsview/qgraphicsview.cpp @@ -829,7 +829,7 @@ void QGraphicsViewPrivate::processPendingUpdates() void QGraphicsViewPrivate::updateAll() { Q_Q(QGraphicsView); - q->viewport()->repaint(); + q->viewport()->update(); fullUpdatePending = true; dirtyBoundingRect = QRect(); dirtyRegion = QRegion(); -- cgit v0.12 From 80321b092fa35eb398f3aaf6a549f20fc4a94624 Mon Sep 17 00:00:00 2001 From: Andreas Aardal Hanssen Date: Tue, 2 Jun 2009 09:23:04 +0200 Subject: Only repaint in QGraphicsViewPrivate::processPendingUpdates() Convert some repaint() calls back to updates(). This ensures that any updates triggered before this call are processed normally, while still keeping the synchronous repaint() call intact. Reviewed-by: bnilsen --- src/gui/graphicsview/qgraphicsview.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp index 7f6fd5e..2515069 100644 --- a/src/gui/graphicsview/qgraphicsview.cpp +++ b/src/gui/graphicsview/qgraphicsview.cpp @@ -846,13 +846,13 @@ void QGraphicsViewPrivate::updateRegion(const QRegion &r) switch (viewportUpdateMode) { case QGraphicsView::FullViewportUpdate: fullUpdatePending = true; - q->viewport()->repaint(); + q->viewport()->update(); break; case QGraphicsView::BoundingRectViewportUpdate: dirtyBoundingRect |= r.boundingRect(); if (dirtyBoundingRect.contains(q->viewport()->rect())) { fullUpdatePending = true; - q->viewport()->repaint(); + q->viewport()->update(); } break; case QGraphicsView::SmartViewportUpdate: // ### DEPRECATE @@ -882,13 +882,13 @@ void QGraphicsViewPrivate::updateRect(const QRect &r) switch (viewportUpdateMode) { case QGraphicsView::FullViewportUpdate: fullUpdatePending = true; - q->viewport()->repaint(); + q->viewport()->update(); break; case QGraphicsView::BoundingRectViewportUpdate: dirtyBoundingRect |= r; if (dirtyBoundingRect.contains(q->viewport()->rect())) { fullUpdatePending = true; - q->viewport()->repaint(); + q->viewport()->update(); } break; case QGraphicsView::SmartViewportUpdate: // ### DEPRECATE -- cgit v0.12 From bc3804458f29c8f13426ef53fcbacbf0877fc896 Mon Sep 17 00:00:00 2001 From: Andreas Aardal Hanssen Date: Tue, 2 Jun 2009 10:14:26 +0200 Subject: Fix QGraphicsScene::drawItems() to use the recursive path as well. This change also changes the direct painting path to be opt-in as a temporary testing measure to see what's broken when using the old code path. --- src/gui/graphicsview/qgraphicsscene.cpp | 130 +++++--------------------------- src/gui/graphicsview/qgraphicsscene_p.h | 2 +- src/gui/graphicsview/qgraphicsview.cpp | 56 +++----------- src/gui/graphicsview/qgraphicsview.h | 2 +- src/gui/graphicsview/qgraphicsview_p.h | 1 + 5 files changed, 34 insertions(+), 157 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index 1d33361..30c7f97 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -5048,6 +5048,7 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * const QTransform &viewTransform, const QRegion &exposedRegion, QWidget *widget, QGraphicsView::OptimizationFlags optimizationFlags, + QList *topLevelItems, qreal parentOpacity) { // Calculate opacity. @@ -5111,7 +5112,7 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * } // Find and sort children. - QList &children = item ? item->d_ptr->children : topLevelItems; + QList &children = item ? item->d_ptr->children : (topLevelItems ? *topLevelItems : this->topLevelItems); if (!dontDrawChildren) { if (item && item->d_ptr->needSortChildren) { item->d_ptr->needSortChildren = 0; @@ -5123,7 +5124,7 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * } // Draw children behind - int i; + int i = 0; if (!dontDrawChildren) { for (i = 0; i < children.size(); ++i) { QGraphicsItem *child = children.at(i); @@ -5131,7 +5132,7 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * break; drawSubtreeRecursive(child, painter, transform, viewTransform, exposedRegion, widget, optimizationFlags, - opacity); + 0, opacity); } } @@ -5160,7 +5161,7 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * if (!dontDrawChildren) { for (; i < children.size(); ++i) { drawSubtreeRecursive(children.at(i), painter, transform, viewTransform, - exposedRegion, widget, optimizationFlags, opacity); + exposedRegion, widget, optimizationFlags, 0, opacity); } } @@ -5321,118 +5322,27 @@ void QGraphicsScene::drawItems(QPainter *painter, const QStyleOptionGraphicsItem options[], QWidget *widget) { Q_D(QGraphicsScene); - - // Detect if painter state protection is disabled. QTransform viewTransform = painter->worldTransform(); - QVarLengthArray childClippers; + Q_UNUSED(options); + // Draw each toplevel recursively. + QGraphicsView *view = widget ? qobject_cast(widget->parentWidget()) : 0; + QList topLevelItems; for (int i = 0; i < numItems; ++i) { - QGraphicsItem *item = items[i]; - if (!(item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren)) { - if (!childClippers.isEmpty()) { - // Item is not clipped to any ancestor: pop all current clippers. - for (int i = 0; i < childClippers.size(); ++i) - painter->restore(); - childClippers.clear(); - } - } else { - // Item is clipped to an ancestor, which may or may not be in our - // child clipper list. Let's start by finding the item's closest - // clipping ancestor. - QGraphicsItem *clipParent = item->parentItem(); - while (clipParent && !(clipParent->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape)) - clipParent = clipParent->parentItem(); - - // Pop any in-between clippers. If the clipper is unknown, pop - // them all. ### QVarLengthArray::lastIndexOf(). - int index = -1; - for (int n = childClippers.size() - 1; n >= 0; --n) { - if (childClippers[n] == clipParent) { - index = n; - break; - } - } - if (index != -1) { - int toPop = childClippers.size() - index - 1; - if (toPop > 0) { - for (int i = 0; i < toPop; ++i) - painter->restore(); - childClippers.resize(index + 1); - } - } - - // Sanity check - if (!childClippers.isEmpty()) - Q_ASSERT(childClippers[childClippers.size() - 1] == clipParent); - - // If the clipper list is empty at this point, but we're still - // clipped to an ancestor, then we need to build the clip chain - // ourselves. There is only one case that can produce this issue: - // This item is stacked behind an ancestor: - // ItemStacksBehindParent. - if (childClippers.isEmpty()) { - Q_ASSERT(clipParent != 0); - // Build a stack of clippers. - QVarLengthArray clippers; - QGraphicsItem *p = clipParent; - do { - if (p->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape) - clippers.append(p); - } while ((p = p->parentItem()) && (p->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren)); - - // ### This code path can also use the itemTransform - // optimization, but it's hit very rarely. - for (int i = clippers.size() - 1; i >= 0; --i) { - QGraphicsItem *clipper = clippers[i]; - painter->setWorldTransform(clipper->deviceTransform(viewTransform), false); - - childClippers.append(clipper); - painter->save(); - painter->setClipPath(clipper->shape(), Qt::IntersectClip); - } - Q_ASSERT(childClippers[childClippers.size() - 1] == clipParent); - } - } - - // Set up the painter transform - if (item->d_ptr->hasValidDeviceTransform) { - painter->setWorldTransform(item->d_ptr->deviceTransform); - item->d_ptr->hasValidDeviceTransform = 0; - } else { - painter->setWorldTransform(item->deviceTransform(viewTransform), false); - } - - // Save painter - bool saveState = (d->painterStateProtection || (item->flags() & QGraphicsItem::ItemClipsToShape)); - if (saveState) - painter->save(); - - // Set local clip - if (item->flags() & QGraphicsItem::ItemClipsToShape) - painter->setClipPath(item->shape(), Qt::IntersectClip); - - // Setup opacity - painter->setOpacity(item->effectiveOpacity()); - - // Draw the item - d->drawItemHelper(item, painter, &options[i], widget, d->painterStateProtection); - const QRect paintedViewBoundingRect = painter->worldTransform().mapRect(options[i].rect).adjusted(-1, -1, 1, 1); - item->d_ptr->paintedViewBoundingRects.insert(widget, paintedViewBoundingRect); - - if (saveState) - painter->restore(); - - if (item->flags() & QGraphicsItem::ItemClipsChildrenToShape) { - // Clip descendents to this item's shape, and keep the painter - // saved. - childClippers.append(item); - painter->save(); - painter->setClipPath(item->shape(), Qt::IntersectClip); + QGraphicsItem *item = items[i]->topLevelItem(); + topLevelItems << item; + + if (!item->d_ptr->itemDiscovered) { + item->d_ptr->itemDiscovered = 1; + d->drawSubtreeRecursive(item, painter, viewTransform, viewTransform, + view->d_func()->exposedRegion, widget, + view->optimizationFlags()); } } - for (int i = 0; i < childClippers.size(); ++i) - painter->restore(); + // Reset discovery bits. + for (int i = 0; i < topLevelItems.size(); ++i) + topLevelItems.at(i)->d_ptr->itemDiscovered = 0; painter->setWorldTransform(viewTransform); } diff --git a/src/gui/graphicsview/qgraphicsscene_p.h b/src/gui/graphicsview/qgraphicsscene_p.h index 4facec3..2a036e3 100644 --- a/src/gui/graphicsview/qgraphicsscene_p.h +++ b/src/gui/graphicsview/qgraphicsscene_p.h @@ -257,7 +257,7 @@ public: void drawSubtreeRecursive(QGraphicsItem *item, QPainter *painter, const QTransform &parentTransform, const QTransform &viewTransform, const QRegion &exposedRegion, QWidget *widget, QGraphicsView::OptimizationFlags optimizationFlags, - qreal parentOpacity = qreal(1.0)); + QList *topLevelItems = 0, qreal parentOpacity = qreal(1.0)); void markDirty(QGraphicsItem *item, const QRectF &rect = QRectF(), bool invalidateChildren = false, bool maybeDirtyClipPath = false, bool force = false, bool ignoreOpacity = false); void processDirtyItemsRecursive(QGraphicsItem *item, const QTransform &); diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp index 2515069..8bafe50 100644 --- a/src/gui/graphicsview/qgraphicsview.cpp +++ b/src/gui/graphicsview/qgraphicsview.cpp @@ -39,8 +39,6 @@ ** ****************************************************************************/ -//#define QGRAPHICSVIEW_DEBUG - static const int QGRAPHICSVIEW_REGION_RECT_THRESHOLD = 50; static const int QGRAPHICSVIEW_PREALLOC_STYLE_OPTIONS = 503; // largest prime < 2^9 @@ -3236,12 +3234,12 @@ void QGraphicsView::paintEvent(QPaintEvent *event) d->scene->d_func()->painterStateProtection = !(d->optimizationFlags & DontSavePainterState); // Determine the exposed region - QRegion exposedRegion = event->region(); + d->exposedRegion = event->region(); if (!d->accelerateScrolling) - exposedRegion = viewport()->rect(); + d->exposedRegion = viewport()->rect(); else if (d->viewportUpdateMode == BoundingRectViewportUpdate) - exposedRegion = event->rect(); - QRectF exposedSceneRect = mapToScene(exposedRegion.boundingRect()).boundingRect(); + d->exposedRegion = event->rect(); + QRectF exposedSceneRect = mapToScene(d->exposedRegion.boundingRect()).boundingRect(); // Set up the painter QPainter painter(viewport()); @@ -3258,16 +3256,7 @@ void QGraphicsView::paintEvent(QPaintEvent *event) const QTransform viewTransform = viewportTransform(); painter.setTransform(viewTransform, true); -#ifdef QGRAPHICSVIEW_DEBUG - QTime stopWatch; - stopWatch.start(); - qDebug() << "QGraphicsView::paintEvent(" << exposedRegion << ')'; -#endif - - // Find all exposed items - bool allItems = false; - QList itemList = d->findItems(exposedRegion, &allItems); - + // Draw background if ((d->cacheMode & CacheBackground) #ifdef Q_WS_X11 && X11->use_xrender @@ -3309,18 +3298,14 @@ void QGraphicsView::paintEvent(QPaintEvent *event) painter.restore(); } -#ifdef QGRAPHICSVIEW_DEBUG - int backgroundTime = stopWatch.elapsed() - exposedTime; -#endif - - static int directEnv = qgetenv("QGRAPHICSVIEW_DIRECT").toInt(); - if (directEnv || (d->optimizationFlags & BypassDrawItems)) { - d->scene->d_func()->drawSubtreeRecursive(0, &painter, viewTransform, viewTransform, exposedRegion, - viewport(), d->optimizationFlags); + // Items + if ((d->optimizationFlags & IndirectPainting)) { + d->scene->d_func()->drawSubtreeRecursive(0, &painter, viewTransform, viewTransform, d->exposedRegion, + viewport(), d->optimizationFlags, 0); } else { // Find all exposed items bool allItems = false; - QList itemList = d->findItems(exposedRegion, &allItems); + QList itemList = d->findItems(d->exposedRegion, &allItems); if (!itemList.isEmpty()) { // Generate the style options. @@ -3328,24 +3313,16 @@ void QGraphicsView::paintEvent(QPaintEvent *event) QGraphicsItem **itemArray = &itemList[0]; // Relies on QList internals, but is perfectly valid. QStyleOptionGraphicsItem *styleOptionArray = d->allocStyleOptionsArray(numItems); for (int i = 0; i < numItems; ++i) - itemArray[i]->d_ptr->initStyleOption(&styleOptionArray[i], viewTransform, exposedRegion, allItems); + itemArray[i]->d_ptr->initStyleOption(&styleOptionArray[i], viewTransform, d->exposedRegion, allItems); // Draw the items. drawItems(&painter, numItems, itemArray, styleOptionArray); d->freeStyleOptionsArray(styleOptionArray); } } -#ifdef QGRAPHICSVIEW_DEBUG - int itemsTime = stopWatch.elapsed() - exposedTime - backgroundTime; -#endif - // Foreground drawForeground(&painter, exposedSceneRect); -#ifdef QGRAPHICSVIEW_DEBUG - int foregroundTime = stopWatch.elapsed() - exposedTime - backgroundTime - itemsTime; -#endif - #ifndef QT_NO_RUBBERBAND // Rubberband if (d->rubberBanding && !d->rubberBandRect.isEmpty()) { @@ -3367,17 +3344,6 @@ void QGraphicsView::paintEvent(QPaintEvent *event) painter.end(); -#ifdef QGRAPHICSVIEW_DEBUG - qDebug() << "\tItem discovery....... " << exposedTime << "msecs (" << itemList.size() << "items," - << (exposedTime > 0 ? (itemList.size() * 1000.0 / exposedTime) : -1) << "/ sec )"; - qDebug() << "\tDrawing background... " << backgroundTime << "msecs (" << exposedRegion.numRects() << "segments )"; - qDebug() << "\tDrawing items........ " << itemsTime << "msecs (" - << (itemsTime > 0 ? (itemList.size() * 1000.0 / itemsTime) : -1) << "/ sec )"; - qDebug() << "\tDrawing foreground... " << foregroundTime << "msecs (" << exposedRegion.numRects() << "segments )"; - qDebug() << "\tTotal rendering time: " << stopWatch.elapsed() << "msecs (" - << (stopWatch.elapsed() > 0 ? (1000.0 / stopWatch.elapsed()) : -1.0) << "fps )"; -#endif - // Restore painter state protection. d->scene->d_func()->painterStateProtection = true; } diff --git a/src/gui/graphicsview/qgraphicsview.h b/src/gui/graphicsview/qgraphicsview.h index deed1d0..b7a9906 100644 --- a/src/gui/graphicsview/qgraphicsview.h +++ b/src/gui/graphicsview/qgraphicsview.h @@ -113,7 +113,7 @@ public: DontClipPainter = 0x1, // obsolete DontSavePainterState = 0x2, DontAdjustForAntialiasing = 0x4, - BypassDrawItems = 0x8 + IndirectPainting = 0x8 }; Q_DECLARE_FLAGS(OptimizationFlags, OptimizationFlag) diff --git a/src/gui/graphicsview/qgraphicsview_p.h b/src/gui/graphicsview/qgraphicsview_p.h index 637687b..814e476 100644 --- a/src/gui/graphicsview/qgraphicsview_p.h +++ b/src/gui/graphicsview/qgraphicsview_p.h @@ -167,6 +167,7 @@ public: void updateRect(const QRect &rect); void updateRegion(const QRegion ®ion); bool updateSceneSlotReimplementedChecked; + QRegion exposedRegion; QList findItems(const QRegion &exposedRegion, bool *allItems) const; }; -- cgit v0.12 From 1fc2406f35594706a9aafa9374694cf0a65cee30 Mon Sep 17 00:00:00 2001 From: Andreas Aardal Hanssen Date: Tue, 2 Jun 2009 11:26:30 +0200 Subject: Refactor QTransform combining code, and mark all code that combines. This change introduces two helper functions in QGraphicsItemPrivate, that combine the item's transform into the current transform, effectively merging the code that calculates any item's combined to-parent transform. This makes the code more readable, and also makes it easier for us to reintroduce the componentized transform API in QGraphicsItem (which was previously reverted). --- src/gui/graphicsview/qgraphicsitem.cpp | 131 +++++++++++++++++++------------- src/gui/graphicsview/qgraphicsitem_p.h | 3 + src/gui/graphicsview/qgraphicsscene.cpp | 30 ++++---- src/gui/graphicsview/qgraphicsview.cpp | 3 +- 4 files changed, 98 insertions(+), 69 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index 0b06613..e1389b5 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -787,6 +787,49 @@ bool QGraphicsItemPrivate::itemIsUntransformable() const || (ancestorFlags & AncestorIgnoresTransformations); } + +/*! + \internal + + Combines this item's position and transform onto \a transform. + + If you need to change this function (e.g., adding more transformation + modes / options), make sure to change all places marked with COMBINE. +*/ +void QGraphicsItemPrivate::combineTransformToParent(QTransform *x, const QTransform *viewTransform) const +{ + // COMBINE + if (viewTransform && itemIsUntransformable()) { + *x = q_ptr->deviceTransform(*viewTransform); + } else { + if (transform) + *x *= *transform; + if (!pos.isNull()) + *x *= QTransform::fromTranslate(pos.x(), pos.y()); + } +} + +/*! + \internal + + Combines this item's position and transform onto \a transform. + + If you need to change this function (e.g., adding more transformation + modes / options), make sure to change QGraphicsItem::deviceTransform() as + well. +*/ +void QGraphicsItemPrivate::combineTransformFromParent(QTransform *x, const QTransform *viewTransform) const +{ + // COMBINE + if (viewTransform && itemIsUntransformable()) { + *x = q_ptr->deviceTransform(*viewTransform); + } else { + x->translate(pos.x(), pos.y()); + if (transform) + *x = *transform * *x; + } +} + /*! \internal @@ -943,6 +986,7 @@ void QGraphicsItemPrivate::childrenBoundingRectHelper(QTransform *x, QRectF *rec QGraphicsItemPrivate *childd = child->d_ptr; bool hasPos = !childd->pos.isNull(); if (hasPos || childd->transform) { + // COMBINE QTransform matrix; if (childd->transform) matrix = *childd->transform; @@ -2667,11 +2711,7 @@ QTransform QGraphicsItem::sceneTransform() const QTransform m; const QGraphicsItem *p = this; do { - if (p->d_ptr->transform) - m *= *p->d_ptr->transform; - const QPointF &pos = p->d_ptr->pos; - if (!pos.isNull()) - m *= QTransform::fromTranslate(pos.x(), pos.y()); + p->d_ptr->combineTransformToParent(&m); } while ((p = p->d_ptr->parent)); return m; } @@ -2723,6 +2763,8 @@ QTransform QGraphicsItem::deviceTransform(const QTransform &viewportTransform) c // First translate the base untransformable item. QPointF mappedPoint = (untransformedAncestor->sceneTransform() * viewportTransform).map(QPointF(0, 0)); + + // COMBINE QTransform matrix; matrix.translate(mappedPoint.x(), mappedPoint.y()); matrix = untransformedAncestor->transform() * matrix; @@ -2730,10 +2772,7 @@ QTransform QGraphicsItem::deviceTransform(const QTransform &viewportTransform) c // Then transform and translate all children. for (int i = 0; i < parents.size(); ++i) { const QGraphicsItem *parent = parents.at(i); - QPointF pos = parent->pos(); - QTransform moveMatrix; - moveMatrix.translate(pos.x(), pos.y()); - matrix = (parent->transform() * moveMatrix) * matrix; + parent->d_ptr->combineTransformFromParent(&matrix); } return matrix; @@ -2776,34 +2815,29 @@ QTransform QGraphicsItem::itemTransform(const QGraphicsItem *other, bool *ok) co if (parent == other) { if (ok) *ok = true; - const QPointF &itemPos = d_ptr->pos; - if (itemPos.isNull()) - return d_ptr->transform ? *d_ptr->transform : QTransform(); - if (d_ptr->transform) - return *d_ptr->transform * QTransform::fromTranslate(itemPos.x(), itemPos.y()); - return QTransform::fromTranslate(itemPos.x(), itemPos.y()); + QTransform x; + d_ptr->combineTransformFromParent(&x); + return x; } // This is other's parent if (otherParent == this) { const QPointF &otherPos = other->d_ptr->pos; if (other->d_ptr->transform) { - QTransform otherToParent = *other->d_ptr->transform; - if (!otherPos.isNull()) - otherToParent *= QTransform::fromTranslate(otherPos.x(), otherPos.y()); + QTransform otherToParent; + other->d_ptr->combineTransformFromParent(&otherToParent); return otherToParent.inverted(ok); - } else { - if (ok) - *ok = true; - return QTransform::fromTranslate(-otherPos.x(), -otherPos.y()); } + if (ok) + *ok = true; + return QTransform::fromTranslate(-otherPos.x(), -otherPos.y()); } // Siblings if (parent == otherParent) { + // COMBINE const QPointF &itemPos = d_ptr->pos; const QPointF &otherPos = other->d_ptr->pos; - if (!d_ptr->transform && !other->d_ptr->transform) { QPointF delta = itemPos - otherPos; if (ok) @@ -2811,14 +2845,10 @@ QTransform QGraphicsItem::itemTransform(const QGraphicsItem *other, bool *ok) co return QTransform::fromTranslate(delta.x(), delta.y()); } - QTransform itemToParent = QTransform::fromTranslate(itemPos.x(), itemPos.y()); - if (d_ptr->transform) - itemToParent = itemPos.isNull() ? *d_ptr->transform : *d_ptr->transform * itemToParent; - - QTransform otherToParent = QTransform::fromTranslate(otherPos.x(), otherPos.y()); - if (other->d_ptr->transform) - otherToParent = otherPos.isNull() ? *other->d_ptr->transform : *other->d_ptr->transform * otherToParent; - + QTransform itemToParent; + d_ptr->combineTransformFromParent(&itemToParent); + QTransform otherToParent; + other->d_ptr->combineTransformFromParent(&otherToParent); return itemToParent * otherToParent.inverted(ok); } @@ -2854,11 +2884,7 @@ QTransform QGraphicsItem::itemTransform(const QGraphicsItem *other, bool *ok) co QTransform x; const QGraphicsItem *p = child; do { - const QGraphicsItemPrivate *pd = p->d_ptr; - if (pd->transform) - x *= *pd->transform; - if (!pd->pos.isNull()) - x *= QTransform::fromTranslate(pd->pos.x(), pd->pos.y()); + p->d_ptr->combineTransformToParent(&x); } while ((p = p->d_ptr->parent) && p != root); if (parentOfOther) return x.inverted(ok); @@ -3206,6 +3232,7 @@ QRectF QGraphicsItem::childrenBoundingRect() const QRectF QGraphicsItem::sceneBoundingRect() const { // Find translate-only offset + // COMBINE QPointF offset; const QGraphicsItem *parentItem = this; const QGraphicsItemPrivate *itemd; @@ -3910,11 +3937,13 @@ void QGraphicsItemPrivate::updateCachedClipPathFromSetPosHelper(const QPointF &n // Find closest clip ancestor and transform. Q_Q(QGraphicsItem); + // COMBINE QTransform thisToParentTransform = transform ? *transform * QTransform::fromTranslate(newPos.x(), newPos.y()) : QTransform::fromTranslate(newPos.x(), newPos.y()); QGraphicsItem *clipParent = parent; while (clipParent && !(clipParent->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape)) { + // COMBINE if (clipParent->d_ptr->transform) thisToParentTransform *= *clipParent->d_ptr->transform; if (!clipParent->d_ptr->pos.isNull()) { @@ -4145,13 +4174,7 @@ void QGraphicsItem::scroll(qreal dx, qreal dy, const QRectF &rect) static const QLineF left(0, 0, -1, 0); static const QLineF right(0, 0, 1, 0); - QTransform deviceTr; - if (d->itemIsUntransformable()) { - deviceTr = deviceTransform(view->viewportTransform()); - } else { - deviceTr = sceneTransform() * view->viewportTransform(); - } - + QTransform deviceTr = deviceTransform(view->viewportTransform()); QRect deviceScrollRect = deviceTr.mapRect(scrollRect).toRect(); QLineF v1 = deviceTr.map(right); QLineF v2 = deviceTr.map(down); @@ -4283,6 +4306,7 @@ QPointF QGraphicsItem::mapToItem(const QGraphicsItem *item, const QPointF &point */ QPointF QGraphicsItem::mapToParent(const QPointF &point) const { + // COMBINE if (!d_ptr->transform) return point + d_ptr->pos; return d_ptr->transform->map(point) + d_ptr->pos; @@ -4350,6 +4374,7 @@ QPolygonF QGraphicsItem::mapToItem(const QGraphicsItem *item, const QRectF &rect */ QPolygonF QGraphicsItem::mapToParent(const QRectF &rect) const { + // COMBINE if (!d_ptr->transform) return rect.translated(d_ptr->pos); return d_ptr->transform->map(rect).translated(d_ptr->pos); @@ -4419,6 +4444,7 @@ QRectF QGraphicsItem::mapRectToItem(const QGraphicsItem *item, const QRectF &rec */ QRectF QGraphicsItem::mapRectToParent(const QRectF &rect) const { + // COMBINE QRectF r = !d_ptr->transform ? rect : d_ptr->transform->mapRect(rect); return r.translated(d_ptr->pos); } @@ -4491,6 +4517,7 @@ QRectF QGraphicsItem::mapRectFromItem(const QGraphicsItem *item, const QRectF &r */ QRectF QGraphicsItem::mapRectFromParent(const QRectF &rect) const { + // COMBINE QRectF r = rect.translated(-d_ptr->pos); return d_ptr->transform ? d_ptr->transform->inverted().mapRect(r) : r; } @@ -4551,6 +4578,7 @@ QPolygonF QGraphicsItem::mapToItem(const QGraphicsItem *item, const QPolygonF &p */ QPolygonF QGraphicsItem::mapToParent(const QPolygonF &polygon) const { + // COMBINE if (!d_ptr->transform) return polygon.translated(d_ptr->pos); return d_ptr->transform->map(polygon).translated(d_ptr->pos); @@ -4595,6 +4623,7 @@ QPainterPath QGraphicsItem::mapToItem(const QGraphicsItem *item, const QPainterP */ QPainterPath QGraphicsItem::mapToParent(const QPainterPath &path) const { + // COMBINE if (!d_ptr->transform) return path.translated(d_ptr->pos); return d_ptr->transform->map(path).translated(d_ptr->pos); @@ -4646,6 +4675,7 @@ QPointF QGraphicsItem::mapFromItem(const QGraphicsItem *item, const QPointF &poi */ QPointF QGraphicsItem::mapFromParent(const QPointF &point) const { + // COMBINE if (d_ptr->transform) return d_ptr->transform->inverted().map(point - d_ptr->pos); return point - d_ptr->pos; @@ -4714,6 +4744,7 @@ QPolygonF QGraphicsItem::mapFromItem(const QGraphicsItem *item, const QRectF &re */ QPolygonF QGraphicsItem::mapFromParent(const QRectF &rect) const { + // COMBINE QRectF r = rect.translated(-d_ptr->pos); return d_ptr->transform ? d_ptr->transform->inverted().map(r) : r; } @@ -4770,6 +4801,7 @@ QPolygonF QGraphicsItem::mapFromItem(const QGraphicsItem *item, const QPolygonF */ QPolygonF QGraphicsItem::mapFromParent(const QPolygonF &polygon) const { + // COMBINE QPolygonF p = polygon; p.translate(-d_ptr->pos); return d_ptr->transform ? d_ptr->transform->inverted().map(p) : p; @@ -4812,6 +4844,7 @@ QPainterPath QGraphicsItem::mapFromItem(const QGraphicsItem *item, const QPainte */ QPainterPath QGraphicsItem::mapFromParent(const QPainterPath &path) const { + // COMBINE QPainterPath p(path); p.translate(-d_ptr->pos); return d_ptr->transform ? d_ptr->transform->inverted().map(p) : p; @@ -5540,21 +5573,13 @@ void QGraphicsItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) if ((item->flags() & ItemIsMovable) && !QGraphicsItemPrivate::movableAncestorIsSelected(item)) { QPointF currentParentPos; QPointF buttonDownParentPos; - if (item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorIgnoresTransformations) { + if (item->d_ptr->itemIsUntransformable()) { // Items whose ancestors ignore transformations need to // map screen coordinates to local coordinates, then map // those to the parent. QTransform viewToItemTransform = (item->deviceTransform(view->viewportTransform())).inverted(); currentParentPos = mapToParent(viewToItemTransform.map(QPointF(view->mapFromGlobal(event->screenPos())))); buttonDownParentPos = mapToParent(viewToItemTransform.map(QPointF(view->mapFromGlobal(event->buttonDownScreenPos(Qt::LeftButton))))); - } else if (item->flags() & ItemIgnoresTransformations) { - // Root items that ignore transformations need to - // calculate their diff by mapping viewport coordinates - // directly to parent coordinates. - QTransform viewToParentTransform = (item->transform().translate(item->d_ptr->pos.x(), item->d_ptr->pos.y())) - * (item->sceneTransform() * view->viewportTransform()).inverted(); - currentParentPos = viewToParentTransform.map(QPointF(view->mapFromGlobal(event->screenPos()))); - buttonDownParentPos = viewToParentTransform.map(QPointF(view->mapFromGlobal(event->buttonDownScreenPos(Qt::LeftButton)))); } else { // All other items simply map from the scene. currentParentPos = item->mapToParent(item->mapFromScene(event->scenePos())); @@ -8884,6 +8909,8 @@ void QGraphicsItemGroup::addToGroup(QGraphicsItem *item) return; } + // COMBINE + // ### Use itemTransform() instead. QTransform oldSceneMatrix = item->sceneTransform(); item->setPos(mapFromItem(item, 0, 0)); item->setParentItem(this); diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index 80b1fb4..7fe7d95 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -163,6 +163,9 @@ public: QPointF genericMapFromScene(const QPointF &pos, const QWidget *viewport) const; bool itemIsUntransformable() const; + void combineTransformToParent(QTransform *x, const QTransform *viewTransform = 0) const; + void combineTransformFromParent(QTransform *x, const QTransform *viewTransform = 0) const; + // ### Qt 5: Remove. Workaround for reimplementation added after Qt 4.4. virtual QVariant inputMethodQueryHelper(Qt::InputMethodQuery query) const; static bool movableAncestorIsSelected(const QGraphicsItem *item); diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index 30c7f97..b1d1742 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -5075,14 +5075,7 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * QRect viewBoundingRect; if (item) { if (!item->d_ptr->hasValidDeviceTransform) { - if (item->d_ptr->itemIsUntransformable()) { - transform = item->deviceTransform(viewTransform); - } else { - const QPointF &pos = item->d_ptr->pos; - transform.translate(pos.x(), pos.y()); - if (item->d_ptr->transform) - transform = *item->d_ptr->transform * transform; - } + item->d_ptr->combineTransformFromParent(&transform, &viewTransform); } else { transform = item->d_ptr->deviceTransform; item->d_ptr->hasValidDeviceTransform = 0; @@ -5226,12 +5219,10 @@ void QGraphicsScenePrivate::processDirtyItemsRecursive(QGraphicsItem *item, cons QTransform transform = parentTransform; if (item) { if (item->d_ptr->itemIsUntransformable()) { - transform = item->deviceTransform(views.at(0)->viewportTransform()); + QTransform x = views.at(0)->viewportTransform(); + item->d_ptr->combineTransformFromParent(&transform, &x); } else { - const QPointF &pos = item->d_ptr->pos; - transform.translate(pos.x(), pos.y()); - if (item->d_ptr->transform) - transform = *item->d_ptr->transform * transform; + item->d_ptr->combineTransformFromParent(&transform); } } @@ -5325,8 +5316,16 @@ void QGraphicsScene::drawItems(QPainter *painter, QTransform viewTransform = painter->worldTransform(); Q_UNUSED(options); - // Draw each toplevel recursively. + // Determine view, expose and flags. QGraphicsView *view = widget ? qobject_cast(widget->parentWidget()) : 0; + QRegion expose; + QGraphicsView::OptimizationFlags flags; + if (view) { + expose = view->d_func()->exposedRegion; + flags = view->optimizationFlags(); + } + + // Draw each toplevel recursively. QList topLevelItems; for (int i = 0; i < numItems; ++i) { QGraphicsItem *item = items[i]->topLevelItem(); @@ -5335,8 +5334,7 @@ void QGraphicsScene::drawItems(QPainter *painter, if (!item->d_ptr->itemDiscovered) { item->d_ptr->itemDiscovered = 1; d->drawSubtreeRecursive(item, painter, viewTransform, viewTransform, - view->d_func()->exposedRegion, widget, - view->optimizationFlags()); + expose, widget, flags); } } diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp index 8bafe50..d410a53 100644 --- a/src/gui/graphicsview/qgraphicsview.cpp +++ b/src/gui/graphicsview/qgraphicsview.cpp @@ -746,6 +746,7 @@ QRect QGraphicsViewPrivate::mapToViewRect(const QGraphicsItem *item, const QRect } // Translate-only + // COMBINE QPointF offset; const QGraphicsItem *parentItem = item; const QGraphicsItemPrivate *itemd; @@ -783,7 +784,7 @@ QRegion QGraphicsViewPrivate::mapToViewRegion(const QGraphicsItem *item, const Q const_cast(this)->updateScroll(); // Accurate bounding region - QTransform itv = item->sceneTransform() * q->viewportTransform(); + QTransform itv = item->deviceTransform(q->viewportTransform()); return item->boundingRegion(itv) & itv.mapRect(rect).toAlignedRect(); } -- cgit v0.12 From 99318bd50bf044c8202f670b667dc990ce90cfe1 Mon Sep 17 00:00:00 2001 From: Andreas Aardal Hanssen Date: Tue, 2 Jun 2009 12:39:02 +0200 Subject: Fix sorting bug and ensure render functions work. Make direct default. Mark the children list for sorting when the Z value for items changes. Change the signature of the recursive draw function slightly so that the expose region is optional, and ensure we don't intersect with this region if it's not available. This change also flips the direct painting so that the default is to use the recursive approach. --- src/gui/graphicsview/qgraphicsitem.cpp | 1 + src/gui/graphicsview/qgraphicsscene.cpp | 24 +++++++++++------------- src/gui/graphicsview/qgraphicsscene_p.h | 2 +- src/gui/graphicsview/qgraphicsview.cpp | 4 ++-- 4 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index e1389b5..17cab45 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -3151,6 +3151,7 @@ void QGraphicsItem::setZValue(qreal z) if (newZ == d_ptr->z) return; d_ptr->z = newZ; + d_ptr->needSortChildren = 1; if (d_ptr->scene) { d_ptr->scene->d_func()->markDirty(this, QRectF(), /*invalidateChildren=*/true); diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index b1d1742..fcb6352 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -2522,7 +2522,6 @@ QList QGraphicsScene::items(const QPointF &pos) const return d->items_helper(pos); } - /*! \fn QList QGraphicsScene::items(const QRectF &rectangle, Qt::ItemSelectionMode mode) const @@ -5046,7 +5045,7 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter *painter, const QTransform &parentTransform, const QTransform &viewTransform, - const QRegion &exposedRegion, QWidget *widget, + QRegion *exposedRegion, QWidget *widget, QGraphicsView::OptimizationFlags optimizationFlags, QList *topLevelItems, qreal parentOpacity) @@ -5084,10 +5083,11 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * if (!brect.size().isNull()) { // ### This does not take the clip into account. _q_adjustRect(&brect); - const QRect paintedViewBoundingRect = transform.mapRect(brect).toRect().adjusted(-1, -1, 1, 1); - item->d_ptr->paintedViewBoundingRects.insert(widget, paintedViewBoundingRect); - viewBoundingRect = paintedViewBoundingRect & exposedRegion.boundingRect(); - } + viewBoundingRect = transform.mapRect(brect).toRect().adjusted(-1, -1, 1, 1); + item->d_ptr->paintedViewBoundingRects.insert(widget, viewBoundingRect); + if (exposedRegion) + viewBoundingRect &= exposedRegion->boundingRect(); + } } bool childClip = (item && (item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape)); @@ -5132,7 +5132,7 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * // Draw item if (!dontDrawItem) { QStyleOptionGraphicsItem option; - item->d_ptr->initStyleOption(&option, transform, exposedRegion); + item->d_ptr->initStyleOption(&option, transform, exposedRegion ? *exposedRegion : QRegion(), exposedRegion == 0); bool clipsToShape = (item->d_ptr->flags & QGraphicsItem::ItemClipsToShape); bool savePainter = clipsToShape || !(optimizationFlags & QGraphicsView::DontSavePainterState); @@ -5143,7 +5143,6 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * if (clipsToShape) painter->setClipPath(item->shape(), Qt::IntersectClip); painter->setOpacity(opacity); - drawItemHelper(item, painter, &option, widget, false); if (savePainter) @@ -5318,20 +5317,19 @@ void QGraphicsScene::drawItems(QPainter *painter, // Determine view, expose and flags. QGraphicsView *view = widget ? qobject_cast(widget->parentWidget()) : 0; - QRegion expose; + QRegion *expose = 0; QGraphicsView::OptimizationFlags flags; if (view) { - expose = view->d_func()->exposedRegion; + expose = &view->d_func()->exposedRegion; flags = view->optimizationFlags(); } - // Draw each toplevel recursively. + // Find all toplevels, they are already sorted. QList topLevelItems; for (int i = 0; i < numItems; ++i) { QGraphicsItem *item = items[i]->topLevelItem(); - topLevelItems << item; - if (!item->d_ptr->itemDiscovered) { + topLevelItems << item; item->d_ptr->itemDiscovered = 1; d->drawSubtreeRecursive(item, painter, viewTransform, viewTransform, expose, widget, flags); diff --git a/src/gui/graphicsview/qgraphicsscene_p.h b/src/gui/graphicsview/qgraphicsscene_p.h index 2a036e3..2e82a4a 100644 --- a/src/gui/graphicsview/qgraphicsscene_p.h +++ b/src/gui/graphicsview/qgraphicsscene_p.h @@ -256,7 +256,7 @@ public: void drawSubtreeRecursive(QGraphicsItem *item, QPainter *painter, const QTransform &parentTransform, const QTransform &viewTransform, - const QRegion &exposedRegion, QWidget *widget, QGraphicsView::OptimizationFlags optimizationFlags, + QRegion *exposedRegion, QWidget *widget, QGraphicsView::OptimizationFlags optimizationFlags, QList *topLevelItems = 0, qreal parentOpacity = qreal(1.0)); void markDirty(QGraphicsItem *item, const QRectF &rect = QRectF(), bool invalidateChildren = false, bool maybeDirtyClipPath = false, bool force = false, bool ignoreOpacity = false); diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp index d410a53..caa3ffc 100644 --- a/src/gui/graphicsview/qgraphicsview.cpp +++ b/src/gui/graphicsview/qgraphicsview.cpp @@ -3300,8 +3300,8 @@ void QGraphicsView::paintEvent(QPaintEvent *event) } // Items - if ((d->optimizationFlags & IndirectPainting)) { - d->scene->d_func()->drawSubtreeRecursive(0, &painter, viewTransform, viewTransform, d->exposedRegion, + if (!(d->optimizationFlags & IndirectPainting)) { + d->scene->d_func()->drawSubtreeRecursive(0, &painter, viewTransform, viewTransform, &d->exposedRegion, viewport(), d->optimizationFlags, 0); } else { // Find all exposed items -- cgit v0.12 From 1b78999dcd5512ce46e2fac20811ad63f3e93ec0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Nilsen?= Date: Tue, 2 Jun 2009 12:46:32 +0200 Subject: Graphics View cleanup: Remove iterative processing of dirty items. The recursive approach is faster and fits better into the new scene transform cache we'll do later. --- src/gui/graphicsview/qgraphicsitem_p.h | 13 ++--- src/gui/graphicsview/qgraphicsscene.cpp | 89 +++------------------------------ src/gui/graphicsview/qgraphicsscene_p.h | 14 ------ 3 files changed, 11 insertions(+), 105 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index 7fe7d95..d962ad0 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -141,12 +141,11 @@ public: emptyClipPath(0), inSetPosHelper(0), needSortChildren(1), + allChildrenDirty(0), + fullUpdatePending(0), flags(0), dirtyChildrenBoundingRect(1), - inDirtyList(0), paintedViewBoundingRectsNeedRepaint(0), - allChildrenDirty(0), - fullUpdatePending(0), hasValidDeviceTransform(0), globalStackingOrder(-1), q_ptr(0) @@ -342,17 +341,15 @@ public: quint32 emptyClipPath : 1; quint32 inSetPosHelper : 1; quint32 needSortChildren : 1; - quint32 unused : 2; + quint32 allChildrenDirty : 1; + quint32 fullUpdatePending : 1; // New 32 bits quint32 flags : 11; quint32 dirtyChildrenBoundingRect : 1; - quint32 inDirtyList : 1; quint32 paintedViewBoundingRectsNeedRepaint : 1; - quint32 allChildrenDirty : 1; - quint32 fullUpdatePending : 1; quint32 hasValidDeviceTransform : 1; - quint32 padding : 15; // feel free to use + quint32 padding : 18; // feel free to use // Optional stacking order int globalStackingOrder; diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index fcb6352..eac057e 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -614,11 +614,6 @@ void QGraphicsScenePrivate::_q_emitUpdated() } } - // Ensure all dirty items's current positions are recorded in the list of - // updated rects. - for (int i = 0; i < dirtyItems.size(); ++i) - updatedRects += dirtyItems.at(i)->sceneBoundingRect(); - // Notify the changes to anybody interested. QList oldUpdatedRects; oldUpdatedRects = updateAll ? (QList() << q->sceneRect()) : updatedRects; @@ -678,74 +673,12 @@ void QGraphicsScenePrivate::_q_polishItems() void QGraphicsScenePrivate::_q_processDirtyItems() { - static int useDirtyListEnv = qgetenv("QT_GV_USE_DIRTY_LIST").toInt(); processDirtyItemsEmitted = false; - if (updateAll) { - if (useDirtyListEnv) { - for (int i = 0; i < dirtyItems.size(); ++i) - resetDirtyItem(dirtyItems.at(i)); - dirtyItems.clear(); - } - return; - } - - if (!useDirtyListEnv) { - processDirtyItemsRecursive(0, views.at(0)->viewportTransform()); - for (int i = 0; i < views.size(); ++i) - views.at(i)->d_func()->processPendingUpdates(); + if (updateAll) return; - } - - for (int i = 0; i < dirtyItems.size(); ++i) { - QGraphicsItem *item = dirtyItems.at(i); - QGraphicsView *view = views.at(0); - QGraphicsViewPrivate *viewPrivate = view->d_func(); - const QTransform deviceTransform = item->deviceTransform(view->viewportTransform()); - QRectF dirtyRect = adjustedItemBoundingRect(item); - if (!item->d_ptr->fullUpdatePending) { - _q_adjustRect(&item->d_ptr->needsRepaint); - dirtyRect &= item->d_ptr->needsRepaint; - } - - if (item->d_ptr->allChildrenDirty && !item->d_ptr->children.isEmpty() - && !item->d_ptr->childrenClippedToShape()) { - QRectF childrenBounds = item->childrenBoundingRect(); - _q_adjustRect(&childrenBounds); - dirtyRect |= childrenBounds; - } - - if (item->d_ptr->paintedViewBoundingRectsNeedRepaint) - viewPrivate->updateRect(item->d_ptr->paintedViewBoundingRects.value(viewPrivate->viewport)); - - bool dirtyRectOutsideViewport = false; - if (item->d_ptr->hasBoundingRegionGranularity) { - const QRegion dirtyViewRegion = deviceTransform.map(QRegion(dirtyRect.toRect())) - & viewPrivate->viewport->rect(); - if (!dirtyViewRegion.isEmpty()) - viewPrivate->updateRegion(dirtyViewRegion); - else - dirtyRectOutsideViewport = true; - } else { - const QRect dirtyViewRect = deviceTransform.mapRect(dirtyRect).toRect() - & viewPrivate->viewport->rect(); - if (!dirtyViewRect.isEmpty()) - viewPrivate->updateRect(dirtyViewRect); - else - dirtyRectOutsideViewport = true; - } - if (!dirtyRectOutsideViewport) { - // We know for sure this item will be process in the paint event, hence - // store its device transform and re-use it when drawing. - item->d_ptr->hasValidDeviceTransform = 1; - item->d_ptr->deviceTransform = deviceTransform; - } - - resetDirtyItem(item); - } - - dirtyItems.clear(); + processDirtyItemsRecursive(0, views.at(0)->viewportTransform()); for (int i = 0; i < views.size(); ++i) views.at(i)->d_func()->processPendingUpdates(); } @@ -808,7 +741,6 @@ void QGraphicsScenePrivate::_q_removeItemLater(QGraphicsItem *item) hoverItems.removeAll(item); cachedItemsUnderMouse.removeAll(item); unpolishedItems.removeAll(item); - removeFromDirtyItems(item); //We remove all references of item from the sceneEventFilter arrays QMultiMap::iterator iterator = sceneEventFilters.begin(); @@ -3347,7 +3279,6 @@ void QGraphicsScene::removeItem(QGraphicsItem *item) d->pendingUpdateItems.removeAll(item); d->cachedItemsUnderMouse.removeAll(item); d->unpolishedItems.removeAll(item); - d->removeFromDirtyItems(item); //We remove all references of item from the sceneEventFilter arrays QMultiMap::iterator iterator = d->sceneEventFilters.begin(); @@ -5195,18 +5126,10 @@ void QGraphicsScenePrivate::markDirty(QGraphicsItem *item, const QRectF &rect, b item->d_ptr->dirtyChildren = 1; } - static int useDirtyListEnv = qgetenv("QT_GV_USE_DIRTY_LIST").toInt(); - if (useDirtyListEnv) { - if (!item->d_ptr->inDirtyList) { - dirtyItems.append(item); - item->d_ptr->inDirtyList = 1; - } - } else { - QGraphicsItem *p = item->d_ptr->parent; - while (p && !p->d_ptr->dirtyChildren) { - p->d_ptr->dirtyChildren = 1; - p = p->d_ptr->parent; - } + QGraphicsItem *p = item->d_ptr->parent; + while (p && !p->d_ptr->dirtyChildren) { + p->d_ptr->dirtyChildren = 1; + p = p->d_ptr->parent; } } diff --git a/src/gui/graphicsview/qgraphicsscene_p.h b/src/gui/graphicsview/qgraphicsscene_p.h index 2e82a4a..9e9ef6b 100644 --- a/src/gui/graphicsview/qgraphicsscene_p.h +++ b/src/gui/graphicsview/qgraphicsscene_p.h @@ -112,7 +112,6 @@ public: QSet selectedItems; QList unindexedItems; QList indexedItems; - QVector dirtyItems; QList pendingUpdateItems; QList unpolishedItems; QList topLevelItems; @@ -268,24 +267,11 @@ public: item->d_ptr->dirty = 0; item->d_ptr->paintedViewBoundingRectsNeedRepaint = 0; item->d_ptr->dirtyChildren = 0; - item->d_ptr->inDirtyList = 0; item->d_ptr->needsRepaint = QRectF(); item->d_ptr->allChildrenDirty = 0; item->d_ptr->fullUpdatePending = 0; } - inline void removeFromDirtyItems(QGraphicsItem *item) - { - int i = 0; - while (i < dirtyItems.size()) { - if (dirtyItems.at(i) == item) - dirtyItems.remove(i); - else - ++i; - } - resetDirtyItem(item); - } - QStyle *style; QFont font; void setFont_helper(const QFont &font); -- cgit v0.12 From d44332954b2a8e66ba4129c230e8ccc65fd972ea Mon Sep 17 00:00:00 2001 From: Andreas Aardal Hanssen Date: Tue, 2 Jun 2009 13:50:28 +0200 Subject: Don't construct new style option objects in a tight loop. The QStyleOption constructor is expensive, as it allocates a QFont, a QPalette and a QFontMetrics. By simply reusing a temporary style option object instead we carve away wasted cycles. Reviewed-by: Ariya --- src/gui/graphicsview/qgraphicsscene.cpp | 17 ++++++++--------- src/gui/graphicsview/qgraphicsscene_p.h | 3 +++ 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index eac057e..0c679de 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -4763,7 +4763,7 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte // Generate the item's exposedRect and map its list of expose // rects to device coordinates. - QStyleOptionGraphicsItem cacheOption = *option; + styleOptionTmp = *option; QRegion pixmapExposed; QRectF exposedRect; if (!itemCache->allExposed) { @@ -4775,11 +4775,11 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte } else { exposedRect = brect; } - cacheOption.exposedRect = exposedRect; + styleOptionTmp.exposedRect = exposedRect; // Render. _q_paintIntoCache(&pix, item, pixmapExposed, itemToPixmap, painter->renderHints(), - &cacheOption, painterStateProtection); + &styleOptionTmp, painterStateProtection); // insert this pixmap into the cache. itemCache->key = QPixmapCache::insert(pix); @@ -4940,12 +4940,12 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte foreach (QRect r, scrollExposure.rects()) br |= pixmapToItem.mapRect(r); } - QStyleOptionGraphicsItem cacheOption = *option; - cacheOption.exposedRect = br.adjusted(-1, -1, 1, 1); + styleOptionTmp = *option; + styleOptionTmp.exposedRect = br.adjusted(-1, -1, 1, 1); // Render the exposed areas. _q_paintIntoCache(&pix, item, pixmapExposed, itemToPixmap, painter->renderHints(), - &cacheOption, painterStateProtection); + &styleOptionTmp, painterStateProtection); // Reset expose data. pixModified = true; @@ -5062,8 +5062,7 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * // Draw item if (!dontDrawItem) { - QStyleOptionGraphicsItem option; - item->d_ptr->initStyleOption(&option, transform, exposedRegion ? *exposedRegion : QRegion(), exposedRegion == 0); + item->d_ptr->initStyleOption(&styleOptionTmp, transform, exposedRegion ? *exposedRegion : QRegion(), exposedRegion == 0); bool clipsToShape = (item->d_ptr->flags & QGraphicsItem::ItemClipsToShape); bool savePainter = clipsToShape || !(optimizationFlags & QGraphicsView::DontSavePainterState); @@ -5074,7 +5073,7 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * if (clipsToShape) painter->setClipPath(item->shape(), Qt::IntersectClip); painter->setOpacity(opacity); - drawItemHelper(item, painter, &option, widget, false); + drawItemHelper(item, painter, &styleOptionTmp, widget, false); if (savePainter) painter->restore(); diff --git a/src/gui/graphicsview/qgraphicsscene_p.h b/src/gui/graphicsview/qgraphicsscene_p.h index 9e9ef6b..d74591c 100644 --- a/src/gui/graphicsview/qgraphicsscene_p.h +++ b/src/gui/graphicsview/qgraphicsscene_p.h @@ -69,6 +69,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -281,6 +282,8 @@ public: void setPalette_helper(const QPalette &palette); void resolvePalette(); void updatePalette(const QPalette &palette); + + QStyleOptionGraphicsItem styleOptionTmp; }; QT_END_NAMESPACE -- cgit v0.12 From 6f218ce216021ff2e8ecf828b2f29b1b9d82b401 Mon Sep 17 00:00:00 2001 From: Andreas Aardal Hanssen Date: Tue, 2 Jun 2009 14:00:03 +0200 Subject: Microoptimize: make this function inline. Also change the order of comparisons, as the transformable flags are most likely to fail first. --- src/gui/graphicsview/qgraphicsitem.cpp | 16 ++-------------- src/gui/graphicsview/qgraphicsitem_p.h | 6 +++++- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index 17cab45..ca39713 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -779,18 +779,6 @@ QPointF QGraphicsItemPrivate::genericMapFromScene(const QPointF &pos, /*! \internal - Returns true if this item or any of its ancestors are untransformable. -*/ -bool QGraphicsItemPrivate::itemIsUntransformable() const -{ - return (flags & QGraphicsItem::ItemIgnoresTransformations) - || (ancestorFlags & AncestorIgnoresTransformations); -} - - -/*! - \internal - Combines this item's position and transform onto \a transform. If you need to change this function (e.g., adding more transformation @@ -799,7 +787,7 @@ bool QGraphicsItemPrivate::itemIsUntransformable() const void QGraphicsItemPrivate::combineTransformToParent(QTransform *x, const QTransform *viewTransform) const { // COMBINE - if (viewTransform && itemIsUntransformable()) { + if (itemIsUntransformable() && viewTransform) { *x = q_ptr->deviceTransform(*viewTransform); } else { if (transform) @@ -821,7 +809,7 @@ void QGraphicsItemPrivate::combineTransformToParent(QTransform *x, const QTransf void QGraphicsItemPrivate::combineTransformFromParent(QTransform *x, const QTransform *viewTransform) const { // COMBINE - if (viewTransform && itemIsUntransformable()) { + if (itemIsUntransformable() && viewTransform) { *x = q_ptr->deviceTransform(*viewTransform); } else { x->translate(pos.x(), pos.y()); diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index d962ad0..61f6496 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -160,7 +160,11 @@ public: void setIsMemberOfGroup(bool enabled); void remapItemPos(QEvent *event, QGraphicsItem *item); QPointF genericMapFromScene(const QPointF &pos, const QWidget *viewport) const; - bool itemIsUntransformable() const; + inline bool itemIsUntransformable() const + { + return (flags & QGraphicsItem::ItemIgnoresTransformations) + || (ancestorFlags & AncestorIgnoresTransformations); + } void combineTransformToParent(QTransform *x, const QTransform *viewTransform = 0) const; void combineTransformFromParent(QTransform *x, const QTransform *viewTransform = 0) const; -- cgit v0.12 From fe640c1245075cabdafa88a16bdd33f9b49452c0 Mon Sep 17 00:00:00 2001 From: Andreas Aardal Hanssen Date: Tue, 2 Jun 2009 16:07:51 +0200 Subject: A faster item discovery function for rectangles (recursive). This function works much faster than the last one, but still it can be much faster. The main expense right now it seems is the transform calculations, and the item->collidesWithPath call. There's still much to gain here. This function does not make use of the BSP tree's fast lookup so it makes lookups slower in (e.g.) the chip demo. --- src/gui/graphicsview/qgraphicsscene.cpp | 110 +++++++++++++++++++++++++++++++- src/gui/graphicsview/qgraphicsscene_p.h | 4 ++ 2 files changed, 113 insertions(+), 1 deletion(-) diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index 0c679de..963c615 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -250,6 +250,8 @@ static const int QGRAPHICSSCENE_INDEXTIMER_TIMEOUT = 2000; QT_BEGIN_NAMESPACE +static inline bool qt_notclosestLeaf(const QGraphicsItem *item1, const QGraphicsItem *item2); + static inline bool QRectF_intersects(const QRectF &s, const QRectF &r) { qreal xp = s.left(); @@ -1372,6 +1374,110 @@ QGraphicsWidget *QGraphicsScenePrivate::windowForItem(const QGraphicsItem *item) return 0; } +void QGraphicsScenePrivate::recursive_items_helper(QGraphicsItem *item, QRectF rect, + QList *items, + const QTransform &parentTransform, + const QTransform &viewTransform, + Qt::ItemSelectionMode mode, Qt::SortOrder order, + qreal parentOpacity) const +{ + // Calculate opacity. + qreal opacity; + if (item) { + if (!item->d_ptr->visible) + return; + QGraphicsItem *p = item->d_ptr->parent; + bool itemIgnoresParentOpacity = item->d_ptr->flags & QGraphicsItem::ItemIgnoresParentOpacity; + bool parentDoesntPropagateOpacity = (p && (p->d_ptr->flags & QGraphicsItem::ItemDoesntPropagateOpacityToChildren)); + if (!itemIgnoresParentOpacity && !parentDoesntPropagateOpacity) { + opacity = parentOpacity * item->opacity(); + } else { + opacity = item->d_ptr->opacity; + } + if (opacity == 0.0 && !(item->d_ptr->flags & QGraphicsItem::ItemDoesntPropagateOpacityToChildren)) + return; + } else { + opacity = parentOpacity; + } + + // Calculate the full transform for this item. + QTransform transform = parentTransform; + bool keep = false; + if (item) { + item->d_ptr->combineTransformFromParent(&transform, &viewTransform); + + QRectF brect = item->boundingRect(); + if (!brect.size().isNull()) { + // ### This does not take the clip into account. + _q_adjustRect(&brect); + + keep = true; + if (mode == Qt::ContainsItemShape || mode == Qt::ContainsItemBoundingRect) + keep = rect.contains(transform.mapRect(brect)); + else + keep = rect.intersects(transform.mapRect(brect)); + + if (keep && (mode == Qt::ContainsItemShape || mode == Qt::IntersectsItemShape)) { + QPainterPath rectPath; + rectPath.addRect(rect); + keep = item->collidesWithPath(transform.inverted().map(rectPath)); + } + } + } + + bool childClip = (item && (item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape)); + bool dontProcessItem = !item || !keep; + bool dontProcessChildren = item && dontProcessItem && childClip; + childClip &= !dontProcessChildren & !children.isEmpty(); + + // Clip. + if (childClip) + rect &= transform.map(item->shape()).controlPointRect(); + + // Find and sort children. + QList &children = item ? item->d_ptr->children : const_cast(this)->topLevelItems; + if (!dontProcessChildren) { + if (item && item->d_ptr->needSortChildren) { + item->d_ptr->needSortChildren = 0; + qStableSort(children.begin(), children.end(), qt_notclosestLeaf); + } else if (!item && needSortTopLevelItems) { + const_cast(this)->needSortTopLevelItems = false; + qStableSort(children.begin(), children.end(), qt_notclosestLeaf); + } + } + + // Process children behind + int i = 0; + if (!dontProcessChildren) { + for (i = 0; i < children.size(); ++i) { + QGraphicsItem *child = children.at(i); + if (!(child->d_ptr->flags & QGraphicsItem::ItemStacksBehindParent)) + break; + recursive_items_helper(child, rect, items, transform, viewTransform, + mode, order, opacity); + } + } + + // Process item + if (!dontProcessItem) + items->append(item); + + // Process children in front + if (!dontProcessChildren) { + for (; i < children.size(); ++i) + recursive_items_helper(children.at(i), rect, items, transform, viewTransform, + mode, order, opacity); + } + + if (!item && order == Qt::AscendingOrder) { + int n = items->size(); + for (int i = 0; i < n / 2; ++i) { + QGraphicsItem *tmp = (*items)[n - i - 1]; + (*items)[n - i - 1] = (*items)[i]; + (*items)[i] = tmp; + } + } +} QList QGraphicsScenePrivate::items_helper(const QPointF &pos) const { @@ -2470,7 +2576,9 @@ QList QGraphicsScene::items(const QPointF &pos) const QList QGraphicsScene::items(const QRectF &rect, Qt::ItemSelectionMode mode) const { Q_D(const QGraphicsScene); - return d->items_helper(rect, mode, Qt::AscendingOrder); + QList itemList; + d->recursive_items_helper(0, rect, &itemList, QTransform(), QTransform(), mode, Qt::AscendingOrder); + return itemList; } /*! diff --git a/src/gui/graphicsview/qgraphicsscene_p.h b/src/gui/graphicsview/qgraphicsscene_p.h index d74591c..6b4476c 100644 --- a/src/gui/graphicsview/qgraphicsscene_p.h +++ b/src/gui/graphicsview/qgraphicsscene_p.h @@ -204,6 +204,10 @@ public: void mousePressEventHandler(QGraphicsSceneMouseEvent *mouseEvent); QGraphicsWidget *windowForItem(const QGraphicsItem *item) const; + void recursive_items_helper(QGraphicsItem *item, QRectF rect, QList *items, + const QTransform &parentTransform, const QTransform &viewTransform, + Qt::ItemSelectionMode mode, Qt::SortOrder order, qreal parentOpacity = 1.0) const; + QList items_helper(const QPointF &pos) const; QList items_helper(const QRectF &rect, Qt::ItemSelectionMode mode, -- cgit v0.12 From de776b777bd9c1884bda4049d8f75020d6092ab7 Mon Sep 17 00:00:00 2001 From: Andreas Aardal Hanssen Date: Tue, 2 Jun 2009 17:27:22 +0200 Subject: Remove crash, remove item from pending updates when deleted. This caused a crash in the contacts demo. --- src/gui/graphicsview/qgraphicsscene.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index 963c615..73d6a93 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -743,6 +743,7 @@ void QGraphicsScenePrivate::_q_removeItemLater(QGraphicsItem *item) hoverItems.removeAll(item); cachedItemsUnderMouse.removeAll(item); unpolishedItems.removeAll(item); + pendingUpdateItems.removeAll(item); //We remove all references of item from the sceneEventFilter arrays QMultiMap::iterator iterator = sceneEventFilters.begin(); -- cgit v0.12 From bdb0c0fc98fc1998f6a7ee21be29513534be3713 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Tue, 2 Jun 2009 20:25:49 +0200 Subject: Optimise effectiveOpacity and make it inlineable. This cut's off some cycles in discardUpdateRequest() which is called from most places when something in the items changes. --- src/gui/graphicsview/qgraphicsitem.cpp | 16 +--------------- src/gui/graphicsview/qgraphicsitem_p.h | 26 +++++++++++++++++++++++++- src/gui/graphicsview/qgraphicsscene.cpp | 4 ++-- 3 files changed, 28 insertions(+), 18 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index ca39713..b913d89 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -2028,21 +2028,7 @@ qreal QGraphicsItem::opacity() const */ qreal QGraphicsItem::effectiveOpacity() const { - if (!d_ptr->parent) - return d_ptr->opacity; - - int myFlags = d_ptr->flags; - int parentFlags = d_ptr->parent ? d_ptr->parent->d_ptr->flags : 0; - - // If I have a parent, and I don't ignore my parent's opacity, and my - // parent propagates to me, then combine my local opacity with my parent's - // effective opacity into my effective opacity. - if (!(myFlags & QGraphicsItem::ItemIgnoresParentOpacity) - && !(parentFlags & QGraphicsItem::ItemDoesntPropagateOpacityToChildren)) { - return d_ptr->opacity * d_ptr->parent->effectiveOpacity(); - } - - return d_ptr->opacity; + return d_ptr->effectiveOpacity(); } /*! diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index 61f6496..d92d76e 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -277,7 +277,31 @@ public: void updateCachedClipPathFromSetPosHelper(const QPointF &newPos); inline bool isFullyTransparent() const - { return q_func()->effectiveOpacity() < .001; } + { return effectiveOpacity() < .001; } + + inline qreal effectiveOpacity() const { + if (!parent) + return opacity; + + qreal o = opacity; + QGraphicsItem *p = parent; + int myFlags = flags; + while (p) { + int parentFlags = p->d_ptr->flags; + + // If I have a parent, and I don't ignore my parent's opacity, and my + // parent propagates to me, then combine my local opacity with my parent's + // effective opacity into my effective opacity. + if ((myFlags & QGraphicsItem::ItemIgnoresParentOpacity) + || (parentFlags & QGraphicsItem::ItemDoesntPropagateOpacityToChildren)) + break; + + o *= parent->d_ptr->opacity; + p = p->d_ptr->parent; + myFlags = parentFlags; + } + return o; + } inline bool childrenCombineOpacity() const { diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index 73d6a93..25ac279 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -419,7 +419,7 @@ QList QGraphicsScenePrivate::estimateItemsInRect(const QRectF & if (QGraphicsItem *item = unindexedItems.at(i)) { if (item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren) continue; - if (item->d_ptr->visible && item->effectiveOpacity() > qreal(0.0)) + if (item->d_ptr->visible && !item->d_ptr->isFullyTransparent()) itemsInRect << item; } } @@ -427,7 +427,7 @@ QList QGraphicsScenePrivate::estimateItemsInRect(const QRectF & if (QGraphicsItem *item = indexedItems.at(i)) { if (item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren) continue; - if (item->d_ptr->visible && item->effectiveOpacity() > qreal(0.0)) + if (item->d_ptr->visible && item->d_ptr->isFullyTransparent()) itemsInRect << item; } } -- cgit v0.12 From 07dca7a30d4bd1efd8032915700420cca3fd60fa Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Tue, 2 Jun 2009 21:02:42 +0200 Subject: implement equality operator in a more sane way Using qFuzzyCompare for checking whether two transformations are equal doesn't give us too much and is inconsistent with our other matrix classes. Using simple floating point equality is a lot faster as well. --- src/gui/painting/qtransform.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/gui/painting/qtransform.cpp b/src/gui/painting/qtransform.cpp index 86e594c..bd2ea31 100644 --- a/src/gui/painting/qtransform.cpp +++ b/src/gui/painting/qtransform.cpp @@ -700,11 +700,15 @@ QTransform & QTransform::rotateRadians(qreal a, Qt::Axis axis) */ bool QTransform::operator==(const QTransform &o) const { -#define qFZ qFuzzyCompare - return qFZ(affine._m11, o.affine._m11) && qFZ(affine._m12, o.affine._m12) && qFZ(m_13, o.m_13) - && qFZ(affine._m21, o.affine._m21) && qFZ(affine._m22, o.affine._m22) && qFZ(m_23, o.m_23) - && qFZ(affine._dx, o.affine._dx) && qFZ(affine._dy, o.affine._dy) && qFZ(m_33, o.m_33); -#undef qFZ + return affine._m11 == o.affine._m11 && + affine._m12 == o.affine._m12 && + affine._m21 == o.affine._m21 && + affine._m22 == o.affine._m22 && + affine._dx == o.affine._dx && + affine._dy == o.affine._dy && + m_13 == o.m_13 && + m_23 == o.m_23 && + m_33 == o.m_33; } /*! -- cgit v0.12 From e5b83ec3dc4e2f4c18b67d45a5699da5a3f05f10 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Tue, 2 Jun 2009 22:05:01 +0200 Subject: optimise isFullyTransparent() This cuts down quite some intructions in some use cases, making esp. discardUpdateRequest() a bit cheaper. --- src/gui/graphicsview/qgraphicsitem_p.h | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index d92d76e..d007f03 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -276,13 +276,8 @@ public: void invalidateCachedClipPathRecursively(bool childrenOnly = false, const QRectF &emptyIfOutsideThisRect = QRectF()); void updateCachedClipPathFromSetPosHelper(const QPointF &newPos); - inline bool isFullyTransparent() const - { return effectiveOpacity() < .001; } - - inline qreal effectiveOpacity() const { - if (!parent) - return opacity; - + inline qreal calcEffectiveOpacity() const + { qreal o = opacity; QGraphicsItem *p = parent; int myFlags = flags; @@ -303,6 +298,23 @@ public: return o; } + inline bool isFullyTransparent() const + { + if (opacity < 0.001) + return true; + if (!parent) + return false; + + return calcEffectiveOpacity() < 0.001; + } + + inline qreal effectiveOpacity() const { + if (!parent || !opacity) + return opacity; + + return calcEffectiveOpacity(); + } + inline bool childrenCombineOpacity() const { if (!children.size()) -- cgit v0.12 From 6887a89b0e0ee7a0eaff2adc34ae71ab01e2ba2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Nilsen?= Date: Tue, 2 Jun 2009 13:53:01 +0200 Subject: Generalize QGrahicsScenePrivate::processDirtyItemsRecursive. Add back compatibility support and make it independent of the views. Also store the sceneTransform instead of the deviceTransform. This will later be the item's cached scene transform (coming in another commit). --- src/gui/graphicsview/qgraphicsitem_p.h | 6 +- src/gui/graphicsview/qgraphicsscene.cpp | 99 ++++++++++++++++++--------------- 2 files changed, 58 insertions(+), 47 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index d007f03..0e0a121 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -146,7 +146,7 @@ public: flags(0), dirtyChildrenBoundingRect(1), paintedViewBoundingRectsNeedRepaint(0), - hasValidDeviceTransform(0), + hasValidSceneTransform(0), globalStackingOrder(-1), q_ptr(0) { @@ -353,7 +353,7 @@ public: QGraphicsItem *parent; QList children; QTransform *transform; - QTransform deviceTransform; + QTransform sceneTransform; int index; int depth; @@ -388,7 +388,7 @@ public: quint32 flags : 11; quint32 dirtyChildrenBoundingRect : 1; quint32 paintedViewBoundingRectsNeedRepaint : 1; - quint32 hasValidDeviceTransform : 1; + quint32 hasValidSceneTransform : 1; quint32 padding : 18; // feel free to use // Optional stacking order diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index 25ac279..34c7dc1 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -680,7 +680,7 @@ void QGraphicsScenePrivate::_q_processDirtyItems() if (updateAll) return; - processDirtyItemsRecursive(0, views.at(0)->viewportTransform()); + processDirtyItemsRecursive(0, QTransform()); for (int i = 0; i < views.size(); ++i) views.at(i)->d_func()->processPendingUpdates(); } @@ -5113,12 +5113,7 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * QTransform transform = parentTransform; QRect viewBoundingRect; if (item) { - if (!item->d_ptr->hasValidDeviceTransform) { - item->d_ptr->combineTransformFromParent(&transform, &viewTransform); - } else { - transform = item->d_ptr->deviceTransform; - item->d_ptr->hasValidDeviceTransform = 0; - } + item->d_ptr->combineTransformFromParent(&transform, &viewTransform); QRectF brect = item->boundingRect(); if (!brect.size().isNull()) { // ### This does not take the clip into account. @@ -5244,51 +5239,67 @@ void QGraphicsScenePrivate::markDirty(QGraphicsItem *item, const QRectF &rect, b void QGraphicsScenePrivate::processDirtyItemsRecursive(QGraphicsItem *item, const QTransform &parentTransform) { Q_ASSERT(!item || item->d_ptr->dirty || item->d_ptr->dirtyChildren); + Q_Q(QGraphicsScene); - // Calculate the full transform for this item. + // Calculate the full scene transform for this item. QTransform transform = parentTransform; - if (item) { - if (item->d_ptr->itemIsUntransformable()) { - QTransform x = views.at(0)->viewportTransform(); - item->d_ptr->combineTransformFromParent(&transform, &x); - } else { - item->d_ptr->combineTransformFromParent(&transform); - } + if (item && !item->d_ptr->itemIsUntransformable()) { + item->d_ptr->combineTransformFromParent(&transform); + item->d_ptr->sceneTransform = transform; + item->d_ptr->hasValidSceneTransform = 1; } // Process item. if (item && item->d_ptr->dirty) { - QRectF dirtyRect = adjustedItemBoundingRect(item); - if (!item->d_ptr->fullUpdatePending) { - _q_adjustRect(&item->d_ptr->needsRepaint); - dirtyRect &= item->d_ptr->needsRepaint; - } + const bool useCompatUpdate = views.isEmpty() || (connectedSignals & changedSignalMask); + if (useCompatUpdate && !item->d_ptr->itemIsUntransformable() + && qFuzzyIsNull(item->boundingRegionGranularity())) { + // This block of code is kept for compatibility. Since 4.5, by default + // QGraphicsView does not connect the signal and we use the below + // method of delivering updates. + q->update(item->sceneBoundingRect()); + } else { + QRectF dirtyRect; + bool uninitializedDirtyRect = true; + + for (int j = 0; j < views.size(); ++j) { + QGraphicsView *view = views.at(j); + QGraphicsViewPrivate *viewPrivate = view->d_func(); + if (viewPrivate->fullUpdatePending) + continue; + switch (viewPrivate->viewportUpdateMode) { + case QGraphicsView::NoViewportUpdate: + continue; + case QGraphicsView::FullViewportUpdate: + view->viewport()->update(); + viewPrivate->fullUpdatePending = 1; + continue; + default: + break; + } - QGraphicsViewPrivate *viewPrivate = views.at(0)->d_func(); - if (item->d_ptr->paintedViewBoundingRectsNeedRepaint) - viewPrivate->updateRect(item->d_ptr->paintedViewBoundingRects.value(viewPrivate->viewport)); + if (uninitializedDirtyRect) { + dirtyRect = adjustedItemBoundingRect(item); + if (!item->d_ptr->fullUpdatePending) { + _q_adjustRect(&item->d_ptr->needsRepaint); + dirtyRect &= item->d_ptr->needsRepaint; + uninitializedDirtyRect = false; + } + } - bool dirtyRectOutsideViewport = false; - if (item->d_ptr->hasBoundingRegionGranularity) { - const QRegion dirtyViewRegion = transform.map(QRegion(dirtyRect.toRect())) - & viewPrivate->viewport->rect(); - if (!dirtyViewRegion.isEmpty()) - viewPrivate->updateRegion(dirtyViewRegion); - else - dirtyRectOutsideViewport = true; - } else { - const QRect dirtyViewRect = transform.mapRect(dirtyRect).toRect() - & viewPrivate->viewport->rect(); - if (!dirtyViewRect.isEmpty()) - viewPrivate->updateRect(dirtyViewRect); - else - dirtyRectOutsideViewport = true; - } - if (!dirtyRectOutsideViewport) { - // We know for sure this item will be process in the paint event, hence - // store its device transform and re-use it when drawing. - item->d_ptr->hasValidDeviceTransform = 1; - item->d_ptr->deviceTransform = transform; + if (item->d_ptr->paintedViewBoundingRectsNeedRepaint) + viewPrivate->updateRect(item->d_ptr->paintedViewBoundingRects.value(viewPrivate->viewport)); + + if (item->d_ptr->hasBoundingRegionGranularity) { + const QRegion dirtyViewRegion = item->deviceTransform(view->viewportTransform()) + .map(QRegion(dirtyRect.toRect())); + viewPrivate->updateRegion(dirtyViewRegion); + } else { + const QRect dirtyViewRect = item->deviceTransform(view->viewportTransform()) + .mapRect(dirtyRect).toRect(); + viewPrivate->updateRect(dirtyViewRect); + } + } } } -- cgit v0.12 From 95949e7ef88eb14b7b22b06d235603f8581f6aa0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Nilsen?= Date: Tue, 2 Jun 2009 18:53:42 +0200 Subject: Cache QGrahicsItem's scene transform. Invalidating the scene transform is just a matter of setting a bit on the item. Then, when we ask for the item's scene transform, we traverse its ancestors recursively and find the top-most dirty item. The algorithm then backtracks to that item and start calculating the scene transform for the item itself and all its children in the call stack. If the item itself and all its ancestors are "clean", nothing is calculated, only traversed. We use this approach when processing dirty items / drawing items as well. That way we ensure the scene transform is only calculated once when absolutely needed. G'night :) --- src/gui/graphicsview/qgraphicsitem.cpp | 50 ++++++++++++++++++--- src/gui/graphicsview/qgraphicsitem_p.h | 11 ++++- src/gui/graphicsview/qgraphicsscene.cpp | 80 ++++++++++++++++++++++----------- src/gui/graphicsview/qgraphicsscene_p.h | 5 +-- src/gui/graphicsview/qgraphicsview.cpp | 2 +- 5 files changed, 109 insertions(+), 39 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index b913d89..57ca2ef 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -952,6 +952,7 @@ void QGraphicsItemPrivate::setParentItemHelper(QGraphicsItem *newParent, bool de // Resolve depth. resolveDepth(parent ? parent->d_ptr->depth : -1); + dirtySceneTransform = 1; // Deliver post-change notification q->itemChange(QGraphicsItem::ItemParentHasChanged, newParentVariant); @@ -2540,6 +2541,7 @@ void QGraphicsItemPrivate::setPosHelper(const QPointF &pos) if (scene) q->prepareGeometryChange(); this->pos = newPos; + dirtySceneTransform = 1; // Send post-notification. #ifndef QGRAPHICSITEM_NO_ITEMCHANGE @@ -2682,12 +2684,17 @@ QMatrix QGraphicsItem::sceneMatrix() const */ QTransform QGraphicsItem::sceneTransform() const { - QTransform m; - const QGraphicsItem *p = this; - do { - p->d_ptr->combineTransformToParent(&m); - } while ((p = p->d_ptr->parent)); - return m; + if (d_ptr->dirtySceneTransform) { + // This item and all its descendants have dirty scene transforms. + // We're about to validate this item's scene transform, so we have to + // invalidate all the children; otherwise there's no way for the descendants + // to detect that the ancestor has changed. + d_ptr->invalidateChildrenSceneTransform(); + } + + QGraphicsItem *that = const_cast(this); + d_ptr->ensureSceneTransformRecursive(&that); + return d_ptr->sceneTransform; } /*! @@ -2899,6 +2906,7 @@ void QGraphicsItem::setMatrix(const QMatrix &matrix, bool combine) // Update and set the new transformation. prepareGeometryChange(); *d_ptr->transform = newTransform; + d_ptr->dirtySceneTransform = 1; // Send post-notification. #ifndef QGRAPHICSITEM_NO_ITEMCHANGE @@ -2945,6 +2953,7 @@ void QGraphicsItem::setTransform(const QTransform &matrix, bool combine) // Update and set the new transformation. prepareGeometryChange(); *d_ptr->transform = newTransform; + d_ptr->dirtySceneTransform = 1; // Send post-notification. itemChange(ItemTransformHasChanged, newTransformVariant); @@ -3966,6 +3975,35 @@ void QGraphicsItemPrivate::updateCachedClipPathFromSetPosHelper(const QPointF &n } } +// Traverses all the ancestors up to the top-level and updates the pointer to +// always point to the top-most item that has a dirty scene transform. +// It then backtracks to the top-most dirty item and start calculating the +// scene transform by combining the item's transform (+pos) with the parent's +// cached scene transform (which we at this point know for sure is valid). +void QGraphicsItemPrivate::ensureSceneTransformRecursive(QGraphicsItem **topMostDirtyItem) +{ + Q_ASSERT(topMostDirtyItem); + + if (dirtySceneTransform) + *topMostDirtyItem = q_ptr; + + if (parent) + parent->d_ptr->ensureSceneTransformRecursive(topMostDirtyItem); + + if (*topMostDirtyItem == q_ptr) { + if (!dirtySceneTransform) + return; // OK, neither my ancestors nor I have dirty scene transforms. + *topMostDirtyItem = 0; + } else if (*topMostDirtyItem) { + return; // Continue backtrack. + } + + // COMBINE my transform with the parent's scene transform. + sceneTransform = parent ? parent->d_ptr->sceneTransform : QTransform(); + combineTransformFromParent(&sceneTransform); + dirtySceneTransform = 0; +} + /*! \internal diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index 0e0a121..f9d63fb 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -146,7 +146,7 @@ public: flags(0), dirtyChildrenBoundingRect(1), paintedViewBoundingRectsNeedRepaint(0), - hasValidSceneTransform(0), + dirtySceneTransform(1), globalStackingOrder(-1), q_ptr(0) { @@ -275,6 +275,13 @@ public: void invalidateCachedClipPathRecursively(bool childrenOnly = false, const QRectF &emptyIfOutsideThisRect = QRectF()); void updateCachedClipPathFromSetPosHelper(const QPointF &newPos); + void ensureSceneTransformRecursive(QGraphicsItem **topMostDirtyItem); + + inline void invalidateChildrenSceneTransform() + { + for (int i = 0; i < children.size(); ++i) + children.at(i)->d_ptr->dirtySceneTransform = 1; + } inline qreal calcEffectiveOpacity() const { @@ -388,7 +395,7 @@ public: quint32 flags : 11; quint32 dirtyChildrenBoundingRect : 1; quint32 paintedViewBoundingRectsNeedRepaint : 1; - quint32 hasValidSceneTransform : 1; + quint32 dirtySceneTransform : 1; quint32 padding : 18; // feel free to use // Optional stacking order diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index 34c7dc1..2773bdd 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -680,7 +680,7 @@ void QGraphicsScenePrivate::_q_processDirtyItems() if (updateAll) return; - processDirtyItemsRecursive(0, QTransform()); + processDirtyItemsRecursive(0); for (int i = 0; i < views.size(); ++i) views.at(i)->d_func()->processPendingUpdates(); } @@ -5083,7 +5083,7 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte } } -void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter *painter, const QTransform &parentTransform, +void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter *painter, const QTransform &viewTransform, QRegion *exposedRegion, QWidget *widget, QGraphicsView::OptimizationFlags optimizationFlags, @@ -5110,10 +5110,24 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * } // Calculate the full transform for this item. - QTransform transform = parentTransform; + QTransform transform; QRect viewBoundingRect; + bool wasDirtyParentSceneTransform = false; if (item) { - item->d_ptr->combineTransformFromParent(&transform, &viewTransform); + if (item->d_ptr->itemIsUntransformable()) { + transform = item->deviceTransform(viewTransform); + } else { + if (item->d_ptr->dirtySceneTransform) { + item->d_ptr->sceneTransform = item->d_ptr->parent ? item->d_ptr->parent->d_ptr->sceneTransform + : transform; + item->d_ptr->combineTransformFromParent(&item->d_ptr->sceneTransform); + item->d_ptr->dirtySceneTransform = 0; + wasDirtyParentSceneTransform = true; + } + transform = item->d_ptr->sceneTransform; + transform *= viewTransform; + } + QRectF brect = item->boundingRect(); if (!brect.size().isNull()) { // ### This does not take the clip into account. @@ -5156,11 +5170,12 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * if (!dontDrawChildren) { for (i = 0; i < children.size(); ++i) { QGraphicsItem *child = children.at(i); + if (wasDirtyParentSceneTransform) + child->d_ptr->dirtySceneTransform = 1; if (!(child->d_ptr->flags & QGraphicsItem::ItemStacksBehindParent)) break; - drawSubtreeRecursive(child, painter, transform, viewTransform, - exposedRegion, widget, optimizationFlags, - 0, opacity); + drawSubtreeRecursive(child, painter, viewTransform, exposedRegion, widget, + optimizationFlags, 0, opacity); } } @@ -5186,9 +5201,14 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * // Draw children in front if (!dontDrawChildren) { for (; i < children.size(); ++i) { - drawSubtreeRecursive(children.at(i), painter, transform, viewTransform, - exposedRegion, widget, optimizationFlags, 0, opacity); + QGraphicsItem *child = children.at(i); + if (wasDirtyParentSceneTransform) + child->d_ptr->dirtySceneTransform = 1; + drawSubtreeRecursive(child, painter, viewTransform, exposedRegion, + widget, optimizationFlags, 0, opacity); } + } else if (wasDirtyParentSceneTransform) { + item->d_ptr->invalidateChildrenSceneTransform(); } // Restore child clip @@ -5236,17 +5256,19 @@ void QGraphicsScenePrivate::markDirty(QGraphicsItem *item, const QRectF &rect, b } } -void QGraphicsScenePrivate::processDirtyItemsRecursive(QGraphicsItem *item, const QTransform &parentTransform) +void QGraphicsScenePrivate::processDirtyItemsRecursive(QGraphicsItem *item) { Q_ASSERT(!item || item->d_ptr->dirty || item->d_ptr->dirtyChildren); Q_Q(QGraphicsScene); // Calculate the full scene transform for this item. - QTransform transform = parentTransform; - if (item && !item->d_ptr->itemIsUntransformable()) { - item->d_ptr->combineTransformFromParent(&transform); - item->d_ptr->sceneTransform = transform; - item->d_ptr->hasValidSceneTransform = 1; + bool wasDirtyParentSceneTransform = false; + if (item && item->d_ptr->dirtySceneTransform && !item->d_ptr->itemIsUntransformable()) { + item->d_ptr->sceneTransform = item->d_ptr->parent ? item->d_ptr->parent->d_ptr->sceneTransform + : QTransform(); + item->d_ptr->combineTransformFromParent(&item->d_ptr->sceneTransform); + item->d_ptr->dirtySceneTransform = 0; + wasDirtyParentSceneTransform = true; } // Process item. @@ -5261,6 +5283,7 @@ void QGraphicsScenePrivate::processDirtyItemsRecursive(QGraphicsItem *item, cons } else { QRectF dirtyRect; bool uninitializedDirtyRect = true; + const bool untransformableItem = item->d_ptr->itemIsUntransformable(); for (int j = 0; j < views.size(); ++j) { QGraphicsView *view = views.at(j); @@ -5290,15 +5313,15 @@ void QGraphicsScenePrivate::processDirtyItemsRecursive(QGraphicsItem *item, cons if (item->d_ptr->paintedViewBoundingRectsNeedRepaint) viewPrivate->updateRect(item->d_ptr->paintedViewBoundingRects.value(viewPrivate->viewport)); - if (item->d_ptr->hasBoundingRegionGranularity) { - const QRegion dirtyViewRegion = item->deviceTransform(view->viewportTransform()) - .map(QRegion(dirtyRect.toRect())); - viewPrivate->updateRegion(dirtyViewRegion); - } else { - const QRect dirtyViewRect = item->deviceTransform(view->viewportTransform()) - .mapRect(dirtyRect).toRect(); - viewPrivate->updateRect(dirtyViewRect); - } + QTransform deviceTransform = item->d_ptr->sceneTransform; + if (!untransformableItem) + deviceTransform *= view->viewportTransform(); + else + deviceTransform = item->deviceTransform(view->viewportTransform()); + if (item->d_ptr->hasBoundingRegionGranularity) + viewPrivate->updateRegion(deviceTransform.map(QRegion(dirtyRect.toRect()))); + else + viewPrivate->updateRect(deviceTransform.mapRect(dirtyRect).toRect()); } } } @@ -5309,14 +5332,18 @@ void QGraphicsScenePrivate::processDirtyItemsRecursive(QGraphicsItem *item, cons const bool allChildrenDirty = item && item->d_ptr->allChildrenDirty; for (int i = 0; i < children->size(); ++i) { QGraphicsItem *child = children->at(i); + if (wasDirtyParentSceneTransform) + child->d_ptr->dirtySceneTransform = 1; if (allChildrenDirty) { child->d_ptr->dirty = 1; } else if (!child->d_ptr->dirty && !child->d_ptr->dirtyChildren) { resetDirtyItem(child); continue; } - processDirtyItemsRecursive(child, transform); + processDirtyItemsRecursive(child); } + } else if (wasDirtyParentSceneTransform) { + item->d_ptr->invalidateChildrenSceneTransform(); } if (item) @@ -5373,8 +5400,7 @@ void QGraphicsScene::drawItems(QPainter *painter, if (!item->d_ptr->itemDiscovered) { topLevelItems << item; item->d_ptr->itemDiscovered = 1; - d->drawSubtreeRecursive(item, painter, viewTransform, viewTransform, - expose, widget, flags); + d->drawSubtreeRecursive(item, painter, viewTransform, expose, widget, flags); } } diff --git a/src/gui/graphicsview/qgraphicsscene_p.h b/src/gui/graphicsview/qgraphicsscene_p.h index 6b4476c..e0c48a6 100644 --- a/src/gui/graphicsview/qgraphicsscene_p.h +++ b/src/gui/graphicsview/qgraphicsscene_p.h @@ -258,13 +258,12 @@ public: const QStyleOptionGraphicsItem *option, QWidget *widget, bool painterStateProtection); - void drawSubtreeRecursive(QGraphicsItem *item, QPainter *painter, const QTransform &parentTransform, - const QTransform &viewTransform, + void drawSubtreeRecursive(QGraphicsItem *item, QPainter *painter, const QTransform &viewTransform, QRegion *exposedRegion, QWidget *widget, QGraphicsView::OptimizationFlags optimizationFlags, QList *topLevelItems = 0, qreal parentOpacity = qreal(1.0)); void markDirty(QGraphicsItem *item, const QRectF &rect = QRectF(), bool invalidateChildren = false, bool maybeDirtyClipPath = false, bool force = false, bool ignoreOpacity = false); - void processDirtyItemsRecursive(QGraphicsItem *item, const QTransform &); + void processDirtyItemsRecursive(QGraphicsItem *item); inline void resetDirtyItem(QGraphicsItem *item) { diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp index caa3ffc..e9a432e 100644 --- a/src/gui/graphicsview/qgraphicsview.cpp +++ b/src/gui/graphicsview/qgraphicsview.cpp @@ -3301,7 +3301,7 @@ void QGraphicsView::paintEvent(QPaintEvent *event) // Items if (!(d->optimizationFlags & IndirectPainting)) { - d->scene->d_func()->drawSubtreeRecursive(0, &painter, viewTransform, viewTransform, &d->exposedRegion, + d->scene->d_func()->drawSubtreeRecursive(0, &painter, viewTransform, &d->exposedRegion, viewport(), d->optimizationFlags, 0); } else { // Find all exposed items -- cgit v0.12 From 062b7b1280ef228567d16187951fe43e2ac0f78c Mon Sep 17 00:00:00 2001 From: Andreas Aardal Hanssen Date: Wed, 3 Jun 2009 07:06:57 +0200 Subject: Remove leftover code from merge conflict. --- src/gui/graphicsview/qgraphicsitem_p.h | 66 ------------- tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp | 126 ------------------------- 2 files changed, 192 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index f9d63fb..b0b940b 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -401,77 +401,11 @@ public: // Optional stacking order int globalStackingOrder; - struct DecomposedTransform; - DecomposedTransform *decomposedTransform() const - { - QGraphicsItemPrivate *that = const_cast(this); - DecomposedTransform *decomposed; - if (hasDecomposedTransform) { - decomposed = qVariantValue(extra(ExtraDecomposedTransform)); - } else { - decomposed = new DecomposedTransform; - that->setExtra(ExtraDecomposedTransform, qVariantFromValue(decomposed)); - that->hasDecomposedTransform = 1; - if (!dirtyTransformComponents) - decomposed->reset(); - } - if (dirtyTransformComponents) { - decomposed->initFrom(q_ptr->transform()); - that->dirtyTransformComponents = 0; - } - return decomposed; - } - - struct DecomposedTransform { - qreal xScale; - qreal yScale; - qreal xRotation; - qreal yRotation; - qreal zRotation; - qreal horizontalShear; - qreal verticalShear; - qreal xOrigin; - qreal yOrigin; - - inline void reset() - { - xScale = 1.0; - yScale = 1.0; - xRotation = 0.0; - yRotation = 0.0; - zRotation = 0.0; - horizontalShear = 0.0; - verticalShear = 0.0; - xOrigin = 0.0; - yOrigin = 0.0; - } - - inline void initFrom(const QTransform &x) - { - reset(); - // ### decompose transform - Q_UNUSED(x); - } - - inline void generateTransform(QTransform *x) const - { - x->translate(xOrigin, yOrigin); - x->rotate(xRotation, Qt::XAxis); - x->rotate(yRotation, Qt::YAxis); - x->rotate(zRotation, Qt::ZAxis); - x->shear(horizontalShear, verticalShear); - x->scale(xScale, yScale); - x->translate(-xOrigin, -yOrigin); - } - }; - QGraphicsItem *q_ptr; }; QT_END_NAMESPACE -Q_DECLARE_METATYPE(QGraphicsItemPrivate::DecomposedTransform *) - #endif // QT_NO_GRAPHICSVIEW #endif diff --git a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp index 8afdeb4..9cfd897 100644 --- a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp +++ b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp @@ -219,8 +219,6 @@ private slots: void updateCachedItemAfterMove(); void deviceTransform_data(); void deviceTransform(); - void setTransformProperties_data(); - void setTransformProperties(); // task specific tests below me void task141694_textItemEnsureVisible(); @@ -6428,129 +6426,5 @@ void tst_QGraphicsItem::deviceTransform() QCOMPARE(rect3->deviceTransform(deviceX).map(QPointF(50, 50)), mapResult3); } -void tst_QGraphicsItem::setTransformProperties_data() -{ - QTest::addColumn("origin"); - QTest::addColumn("rotationX"); - QTest::addColumn("rotationY"); - QTest::addColumn("rotationZ"); - QTest::addColumn("scaleX"); - QTest::addColumn("scaleY"); - QTest::addColumn("shearX"); - QTest::addColumn("shearY"); - - QTest::newRow("nothing") << QPointF() << qreal(0.0) << qreal(0.0) << qreal(0.0) - << qreal(1) << qreal(1) << qreal(0.0) << qreal(0.0); - - QTest::newRow("rotationZ") << QPointF() << qreal(0.0) << qreal(0.0) << qreal(42.2) - << qreal(1) << qreal(1) << qreal(0.0) << qreal(0.0); - - QTest::newRow("rotationXY") << QPointF() << qreal(12.5) << qreal(53.6) << qreal(0.0) - << qreal(1) << qreal(1) << qreal(0.0) << qreal(0.0); - - QTest::newRow("rotationXYZ") << QPointF() << qreal(-25) << qreal(12) << qreal(556) - << qreal(1) << qreal(1) << qreal(0.0) << qreal(0.0); - - QTest::newRow("rotationXYZ dicentred") << QPointF(-53, 25.2) - << qreal(-2578.2) << qreal(4565.2) << qreal(56) - << qreal(1) << qreal(1) << qreal(0.0) << qreal(0.0); - - QTest::newRow("Scale") << QPointF() << qreal(0.0) << qreal(0.0) << qreal(0.0) - << qreal(6) << qreal(0.5) << qreal(0.0) << qreal(0.0); - - QTest::newRow("Shear") << QPointF() << qreal(0.0) << qreal(0.0) << qreal(0.0) - << qreal(1) << qreal(1) << qreal(2.2) << qreal(0.5); - - QTest::newRow("Scale and Shear") << QPointF() << qreal(0.0) << qreal(0.0) << qreal(0.0) - << qreal(5.2) << qreal(2.1) << qreal(5.2) << qreal(5.5); - - QTest::newRow("Everything") << QPointF() << qreal(41) << qreal(-23) << qreal(0.56) - << qreal(8.2) << qreal(-0.2) << qreal(-12) << qreal(-0.8); - - QTest::newRow("Everything dicentred") << QPointF(qreal(22.3), qreal(-56.2)) << qreal(-175) << qreal(196) << qreal(-1260) - << qreal(4) << qreal(2) << qreal(2.56) << qreal(0.8); -} - -void tst_QGraphicsItem::setTransformProperties() -{ - QFETCH(QPointF,origin); - QFETCH(qreal,rotationX); - QFETCH(qreal,rotationY); - QFETCH(qreal,rotationZ); - QFETCH(qreal,scaleX); - QFETCH(qreal,scaleY); - QFETCH(qreal,shearX); - QFETCH(qreal,shearY); - - QTransform result; - result.translate(origin.x(), origin.y()); - result.rotate(rotationX, Qt::XAxis); - result.rotate(rotationY, Qt::YAxis); - result.rotate(rotationZ, Qt::ZAxis); - result.shear(shearX, shearY); - result.scale(scaleX, scaleY); - result.translate(-origin.x(), -origin.y()); - - QGraphicsScene scene; - QGraphicsRectItem *item = new QGraphicsRectItem(QRectF(0, 0, 100, 100)); - scene.addItem(item); - item->setPos(100, 100); - - item->setRotation(rotationX, rotationY, rotationZ); - item->setScale(scaleX, scaleY); - item->setShear(shearX, shearY); - item->setTransformOrigin(origin); - - QCOMPARE(item->xRotation(), rotationX); - QCOMPARE(item->yRotation(), rotationY); - QCOMPARE(item->zRotation(), rotationZ); - QCOMPARE(item->xScale(), scaleX); - QCOMPARE(item->yScale(), scaleY); - QCOMPARE(item->horizontalShear(), shearX); - QCOMPARE(item->verticalShear(), shearY); - QCOMPARE(item->transformOrigin(), origin); - - QCOMPARE(result, item->transform()); - - //----------------------------------------------------------------- - //Change the rotation Z - item->setZRotation(45); - QTransform result2; - result2.translate(origin.x(), origin.y()); - result2.rotate(rotationX, Qt::XAxis); - result2.rotate(rotationY, Qt::YAxis); - result2.rotate(45, Qt::ZAxis); - result2.shear(shearX, shearY); - result2.scale(scaleX, scaleY); - result2.translate(-origin.x(), -origin.y()); - - QCOMPARE(item->xRotation(), rotationX); - QCOMPARE(item->yRotation(), rotationY); - QCOMPARE(item->zRotation(), 45.0); - QCOMPARE(item->xScale(), scaleX); - QCOMPARE(item->yScale(), scaleY); - QCOMPARE(item->horizontalShear(), shearX); - QCOMPARE(item->verticalShear(), shearY); - QCOMPARE(item->transformOrigin(), origin); - - QCOMPARE(result2, item->transform()); - - //----------------------------------------------------------------- - // calling setTransform() should reset the properties to their default - item->setTransform(result); - - QCOMPARE(item->xRotation(), 0.0); - QCOMPARE(item->yRotation(), 0.0); - QCOMPARE(item->zRotation(), 0.0); - QCOMPARE(item->xScale(), 1.0); - QCOMPARE(item->yScale(), 1.0); - QCOMPARE(item->horizontalShear(), 0.0); - QCOMPARE(item->verticalShear(), 0.0); - QCOMPARE(item->transformOrigin(), QPointF(0,0)); - - QCOMPARE(result, item->transform()); -} - - QTEST_MAIN(tst_QGraphicsItem) #include "tst_qgraphicsitem.moc" -- cgit v0.12 From 8af81877bb11d58099189bfab21d21e3021b7b8b Mon Sep 17 00:00:00 2001 From: Andreas Aardal Hanssen Date: Wed, 3 Jun 2009 07:35:06 +0200 Subject: Add QGraphicsView::isTransformed(), and use it to avoid view transforms. Ensure that we don't ask for or multiply with the view transform if the view is not transformed. --- src/gui/graphicsview/qgraphicsscene.cpp | 10 ++++++---- src/gui/graphicsview/qgraphicsview.cpp | 12 ++++++++++++ src/gui/graphicsview/qgraphicsview.h | 1 + 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index 2773bdd..7bf58c3 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -5314,10 +5314,12 @@ void QGraphicsScenePrivate::processDirtyItemsRecursive(QGraphicsItem *item) viewPrivate->updateRect(item->d_ptr->paintedViewBoundingRects.value(viewPrivate->viewport)); QTransform deviceTransform = item->d_ptr->sceneTransform; - if (!untransformableItem) - deviceTransform *= view->viewportTransform(); - else - deviceTransform = item->deviceTransform(view->viewportTransform()); + if (view->isTransformed()) { + if (!untransformableItem) + deviceTransform *= view->viewportTransform(); + else + deviceTransform = item->deviceTransform(view->viewportTransform()); + } if (item->d_ptr->hasBoundingRegionGranularity) viewPrivate->updateRegion(deviceTransform.map(QRegion(dirtyRect.toRect()))); else diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp index e9a432e..c91e0d1 100644 --- a/src/gui/graphicsview/qgraphicsview.cpp +++ b/src/gui/graphicsview/qgraphicsview.cpp @@ -3555,6 +3555,18 @@ QTransform QGraphicsView::viewportTransform() const } /*! + Returns true if the view is transformed (i.e., a non-identity transform + has been assigned, or the scrollbars are adjusted). + + \sa setTransform(), horizontalScrollBar(), verticalScrollBar() +*/ +bool QGraphicsView::isTransformed() const +{ + Q_D(const QGraphicsView); + return !d->identityMatrix || d->horizontalScroll() || d->verticalScroll(); +} + +/*! Sets the view's current transformation matrix to \a matrix. If \a combine is true, then \a matrix is combined with the current matrix; diff --git a/src/gui/graphicsview/qgraphicsview.h b/src/gui/graphicsview/qgraphicsview.h index b7a9906..387fa01 100644 --- a/src/gui/graphicsview/qgraphicsview.h +++ b/src/gui/graphicsview/qgraphicsview.h @@ -170,6 +170,7 @@ public: void resetMatrix(); QTransform transform() const; QTransform viewportTransform() const; + bool isTransformed() const; void setTransform(const QTransform &matrix, bool combine = false); void resetTransform(); void rotate(qreal angle); -- cgit v0.12 From b5d987298b0502dd593dd09d7e4e1233d6e30dd6 Mon Sep 17 00:00:00 2001 From: Andreas Aardal Hanssen Date: Wed, 3 Jun 2009 07:50:33 +0200 Subject: Avoid constructing empty temporary QTransforms. This is a microoptimization. --- src/gui/graphicsview/qgraphicsscene.cpp | 19 +++++++++---------- src/gui/graphicsview/qgraphicsscene_p.h | 1 + 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index 7bf58c3..188165d 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -5110,29 +5110,28 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * } // Calculate the full transform for this item. - QTransform transform; QRect viewBoundingRect; bool wasDirtyParentSceneTransform = false; if (item) { if (item->d_ptr->itemIsUntransformable()) { - transform = item->deviceTransform(viewTransform); + transformTmp = item->deviceTransform(viewTransform); } else { if (item->d_ptr->dirtySceneTransform) { item->d_ptr->sceneTransform = item->d_ptr->parent ? item->d_ptr->parent->d_ptr->sceneTransform - : transform; + : QTransform(); item->d_ptr->combineTransformFromParent(&item->d_ptr->sceneTransform); item->d_ptr->dirtySceneTransform = 0; wasDirtyParentSceneTransform = true; } - transform = item->d_ptr->sceneTransform; - transform *= viewTransform; + transformTmp = item->d_ptr->sceneTransform; + transformTmp *= viewTransform; } - + QRectF brect = item->boundingRect(); if (!brect.size().isNull()) { // ### This does not take the clip into account. _q_adjustRect(&brect); - viewBoundingRect = transform.mapRect(brect).toRect().adjusted(-1, -1, 1, 1); + viewBoundingRect = transformTmp.mapRect(brect).toRect().adjusted(-1, -1, 1, 1); item->d_ptr->paintedViewBoundingRects.insert(widget, viewBoundingRect); if (exposedRegion) viewBoundingRect &= exposedRegion->boundingRect(); @@ -5149,7 +5148,7 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * // Clip children. if (childClip) { painter->save(); - painter->setWorldTransform(transform); + painter->setWorldTransform(transformTmp); painter->setClipPath(item->shape(), Qt::IntersectClip); } @@ -5181,14 +5180,14 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * // Draw item if (!dontDrawItem) { - item->d_ptr->initStyleOption(&styleOptionTmp, transform, exposedRegion ? *exposedRegion : QRegion(), exposedRegion == 0); + item->d_ptr->initStyleOption(&styleOptionTmp, transformTmp, exposedRegion ? *exposedRegion : QRegion(), exposedRegion == 0); bool clipsToShape = (item->d_ptr->flags & QGraphicsItem::ItemClipsToShape); bool savePainter = clipsToShape || !(optimizationFlags & QGraphicsView::DontSavePainterState); if (savePainter) painter->save(); if (!childClip) - painter->setWorldTransform(transform); + painter->setWorldTransform(transformTmp); if (clipsToShape) painter->setClipPath(item->shape(), Qt::IntersectClip); painter->setOpacity(opacity); diff --git a/src/gui/graphicsview/qgraphicsscene_p.h b/src/gui/graphicsview/qgraphicsscene_p.h index e0c48a6..8bc25b6 100644 --- a/src/gui/graphicsview/qgraphicsscene_p.h +++ b/src/gui/graphicsview/qgraphicsscene_p.h @@ -287,6 +287,7 @@ public: void updatePalette(const QPalette &palette); QStyleOptionGraphicsItem styleOptionTmp; + QTransform transformTmp; }; QT_END_NAMESPACE -- cgit v0.12 From 31a7de5cbecad8f5cc106c8886c79c63f07c9b5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Nilsen?= Date: Wed, 3 Jun 2009 10:43:49 +0200 Subject: Correct minor mistake after re-refactoring. We don't want to re-calculate the dirty rect for each view. --- src/gui/graphicsview/qgraphicsscene.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index 188165d..f8b3b0a 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -5305,8 +5305,8 @@ void QGraphicsScenePrivate::processDirtyItemsRecursive(QGraphicsItem *item) if (!item->d_ptr->fullUpdatePending) { _q_adjustRect(&item->d_ptr->needsRepaint); dirtyRect &= item->d_ptr->needsRepaint; - uninitializedDirtyRect = false; } + uninitializedDirtyRect = false; } if (item->d_ptr->paintedViewBoundingRectsNeedRepaint) -- cgit v0.12 From 33473417a73cafa0c0d9283c00b1e716becba0e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Nilsen?= Date: Wed, 3 Jun 2009 14:34:54 +0200 Subject: Speed up processing of dirty items when ancestor clips children. This patch also contains a bug fix where a child item didn't update due to a bit not being properly set. No more rendering artifacts :) --- src/gui/graphicsview/qgraphicsscene.cpp | 33 +++++++++++++++++++++++++++------ src/gui/graphicsview/qgraphicsscene_p.h | 2 +- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index f8b3b0a..ec0e87b 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -5255,7 +5255,7 @@ void QGraphicsScenePrivate::markDirty(QGraphicsItem *item, const QRectF &rect, b } } -void QGraphicsScenePrivate::processDirtyItemsRecursive(QGraphicsItem *item) +void QGraphicsScenePrivate::processDirtyItemsRecursive(QGraphicsItem *item, bool dirtyAncestorContainsChildren) { Q_ASSERT(!item || item->d_ptr->dirty || item->d_ptr->dirtyChildren); Q_Q(QGraphicsScene); @@ -5271,7 +5271,7 @@ void QGraphicsScenePrivate::processDirtyItemsRecursive(QGraphicsItem *item) } // Process item. - if (item && item->d_ptr->dirty) { + if (item && (item->d_ptr->dirty || item->d_ptr->paintedViewBoundingRectsNeedRepaint)) { const bool useCompatUpdate = views.isEmpty() || (connectedSignals & changedSignalMask); if (useCompatUpdate && !item->d_ptr->itemIsUntransformable() && qFuzzyIsNull(item->boundingRegionGranularity())) { @@ -5300,6 +5300,12 @@ void QGraphicsScenePrivate::processDirtyItemsRecursive(QGraphicsItem *item) break; } + if (item->d_ptr->paintedViewBoundingRectsNeedRepaint) + viewPrivate->updateRect(item->d_ptr->paintedViewBoundingRects.value(viewPrivate->viewport)); + + if (!item->d_ptr->dirty) + continue; + if (uninitializedDirtyRect) { dirtyRect = adjustedItemBoundingRect(item); if (!item->d_ptr->fullUpdatePending) { @@ -5309,9 +5315,6 @@ void QGraphicsScenePrivate::processDirtyItemsRecursive(QGraphicsItem *item) uninitializedDirtyRect = false; } - if (item->d_ptr->paintedViewBoundingRectsNeedRepaint) - viewPrivate->updateRect(item->d_ptr->paintedViewBoundingRects.value(viewPrivate->viewport)); - QTransform deviceTransform = item->d_ptr->sceneTransform; if (view->isTransformed()) { if (!untransformableItem) @@ -5331,17 +5334,35 @@ void QGraphicsScenePrivate::processDirtyItemsRecursive(QGraphicsItem *item) if (!item || item->d_ptr->dirtyChildren) { QList *children = item ? &item->d_ptr->children : &topLevelItems; const bool allChildrenDirty = item && item->d_ptr->allChildrenDirty; + if (!dirtyAncestorContainsChildren) { + dirtyAncestorContainsChildren = item && item->d_ptr->fullUpdatePending + && (item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape); + } for (int i = 0; i < children->size(); ++i) { QGraphicsItem *child = children->at(i); if (wasDirtyParentSceneTransform) child->d_ptr->dirtySceneTransform = 1; + if (allChildrenDirty) { child->d_ptr->dirty = 1; + child->d_ptr->fullUpdatePending = 1; + child->d_ptr->dirtyChildren = 1; + child->d_ptr->allChildrenDirty = 1; } else if (!child->d_ptr->dirty && !child->d_ptr->dirtyChildren) { resetDirtyItem(child); continue; } - processDirtyItemsRecursive(child); + + if (dirtyAncestorContainsChildren) { + // No need to process this child's dirty rect, hence reset the dirty state. + // However, we have to continue the recursion because it might have a dirty + // view bounding rect that needs repaint. We also have to reset the dirty + // state of its descendants. + child->d_ptr->dirty = 0; + child->d_ptr->fullUpdatePending = 0; + } + + processDirtyItemsRecursive(child, dirtyAncestorContainsChildren); } } else if (wasDirtyParentSceneTransform) { item->d_ptr->invalidateChildrenSceneTransform(); diff --git a/src/gui/graphicsview/qgraphicsscene_p.h b/src/gui/graphicsview/qgraphicsscene_p.h index 8bc25b6..f4964f2 100644 --- a/src/gui/graphicsview/qgraphicsscene_p.h +++ b/src/gui/graphicsview/qgraphicsscene_p.h @@ -263,7 +263,7 @@ public: QList *topLevelItems = 0, qreal parentOpacity = qreal(1.0)); void markDirty(QGraphicsItem *item, const QRectF &rect = QRectF(), bool invalidateChildren = false, bool maybeDirtyClipPath = false, bool force = false, bool ignoreOpacity = false); - void processDirtyItemsRecursive(QGraphicsItem *item); + void processDirtyItemsRecursive(QGraphicsItem *item, bool dirtyAncestorContainsChildren = false); inline void resetDirtyItem(QGraphicsItem *item) { -- cgit v0.12 From 1598ef761a8c3f0c9cccf5318e3de30f6c50880f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Nilsen?= Date: Wed, 3 Jun 2009 15:18:25 +0200 Subject: Compatibility fix: Updates made on the scene must be processed with a queued connection This connection was queued in the views before, but we don't do that anymore, instead we re-use the _q_emitUpdated slot and process pending updates on the views there. Makes tst_QGraphicsView::viewportUpdateMode happy again. --- src/gui/graphicsview/qgraphicsscene.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index ec0e87b..8641fe2 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -614,6 +614,10 @@ void QGraphicsScenePrivate::_q_emitUpdated() views.at(i), SLOT(updateScene(QList))); } } + } else { + for (int i = 0; i < views.size(); ++i) + views.at(i)->d_func()->processPendingUpdates(); + return; } // Notify the changes to anybody interested. @@ -3721,7 +3725,7 @@ void QGraphicsScene::update(const QRectF &rect) } } - if (!directUpdates && !d->calledEmitUpdated) { + if (!d->calledEmitUpdated) { d->calledEmitUpdated = true; QMetaObject::invokeMethod(this, "_q_emitUpdated", Qt::QueuedConnection); } -- cgit v0.12 From 728179ed60b43187d28c77a2d6930a74a62791d6 Mon Sep 17 00:00:00 2001 From: Andreas Aardal Hanssen Date: Wed, 3 Jun 2009 16:34:58 +0200 Subject: Add QGraphicsItem::itemChangeEnabled(). This function allows the user to disable notifications for item changes. In QSimpleCanvasItem, all notifications are disabled by default, and you can enable them one at a time. QGraphicsItem's behavior is to by default enable all notifications. A side effect of this change is that I've removed one optimization in favor of another: by not constructing a QVariant at all when there's no notification we get maximum performance, at the expense of constructing it twice if there is a notification. --- src/gui/graphicsview/qgraphicsitem.cpp | 251 ++++++++++++++++++++++---------- src/gui/graphicsview/qgraphicsitem.h | 5 + src/gui/graphicsview/qgraphicsitem_p.h | 4 +- src/gui/graphicsview/qgraphicsscene.cpp | 30 ++-- 4 files changed, 202 insertions(+), 88 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index 57ca2ef..2eb5150 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -39,8 +39,6 @@ ** ****************************************************************************/ -#define QGRAPHICSITEM_NO_ITEMCHANGE - /*! \class QGraphicsItem \brief The QGraphicsItem class is the base class for all graphical @@ -851,11 +849,13 @@ void QGraphicsItemPrivate::setParentItemHelper(QGraphicsItem *newParent, bool de if (newParent == parent) return; - const QVariant newParentVariant(q->itemChange(QGraphicsItem::ItemParentChange, - qVariantFromValue(newParent))); - newParent = qVariantValue(newParentVariant); - if (newParent == parent) - return; + bool notify = q->itemChangeEnabled(QGraphicsItem::ItemParentChange); + if (notify) { + newParent = qVariantValue(q->itemChange(QGraphicsItem::ItemParentChange, + qVariantFromValue(newParent))); + if (newParent == parent) + return; + } if (QGraphicsWidget *w = isWidget ? static_cast(q) : q->parentWidget()) { // Update the child focus chain; when reparenting a widget that has a @@ -955,7 +955,8 @@ void QGraphicsItemPrivate::setParentItemHelper(QGraphicsItem *newParent, bool de dirtySceneTransform = 1; // Deliver post-change notification - q->itemChange(QGraphicsItem::ItemParentHasChanged, newParentVariant); + if (notify) + q->itemChange(QGraphicsItem::ItemParentHasChanged, qVariantFromValue(newParent)); } /*! @@ -1393,9 +1394,14 @@ void QGraphicsItem::setFlags(GraphicsItemFlags flags) // Notify change and check for adjustment. if (quint32(d_ptr->flags) == quint32(flags)) return; - flags = GraphicsItemFlags(itemChange(ItemFlagsChange, quint32(flags)).toUInt()); - if (quint32(d_ptr->flags) == quint32(flags)) - return; + + // Notify + bool notify = itemChangeEnabled(ItemFlagsChange); + if (notify) { + flags = GraphicsItemFlags(itemChange(ItemFlagsChange, quint32(flags)).toUInt()); + if (quint32(d_ptr->flags) == quint32(flags)) + return; + } // Flags that alter the geometry of the item (or its children). const quint32 geomChangeFlagsMask = (ItemClipsChildrenToShape | ItemClipsToShape | ItemIgnoresTransformations); @@ -1443,7 +1449,78 @@ void QGraphicsItem::setFlags(GraphicsItemFlags flags) } // Notify change. - itemChange(ItemFlagsHaveChanged, quint32(flags)); + if (notify) + itemChange(ItemFlagsHaveChanged, quint32(flags)); +} + +static const int itemChangeBits[] = { + /* ItemPositionChange */ 1 << 1, + /* ItemMatrixChange */ 1 << 2, + /* ItemVisibleChange */ 1 << 3, + /* ItemEnabledChange */ 1 << 4, + /* ItemSelectedChange */ 1 << 5, + /* ItemParentChange */ 1 << 6, + /* ItemChildAddedChange */ 1 << 7, + /* ItemChildRemovedChange */ 1 << 8, + /* ItemTransformChange */ 1 << 9, + /* ItemPositionHasChanged */ 1 << 1, + /* ItemTransformHasChanged */ 1 << 9, + /* ItemSceneChange */ 1 << 10, + /* ItemVisibleHasChanged */ 1 << 3, + /* ItemEnabledHasChanged */ 1 << 4, + /* ItemSelectedHasChanged */ 1 << 5, + /* ItemParentHasChanged */ 1 << 6, + /* ItemSceneHasChanged */ 1 << 10, + /* ItemCursorChange */ 1 << 11, + /* ItemCursorHasChanged */ 1 << 11, + /* ItemToolTipChange */ 1 << 12, + /* ItemToolTipHasChanged */ 1 << 12, + /* ItemFlagsChange */ 1 << 13, + /* ItemFlagsHaveChanged */ 1 << 13, + /* ItemZValueChange */ 1 << 14, + /* ItemZValueHasChanged */ 1 << 14, + /* ItemOpacityChange */ 1 << 15, + /* ItemOpacityHasChanged */ 1 << 15 +}; + +/*! + Returns true if \a change is enabled (i.e., QGraphicsItem will call + itemChange() whenever the respective change occurs); otherwise returns + false. + + \sa setItemChangeEnabled(), setItemChangesEnabled(), itemChange() +*/ +bool QGraphicsItem::itemChangeEnabled(GraphicsItemChange change) const +{ + return d_ptr->itemChangesEnabled & itemChangeBits[change]; +} + +/*! + If \a enabled is true, notifications for \a change are enabled; otherwise + they are disabled. By default, QGraphicsItem sends notifications for all + changes by calling itemChange(). + + \sa itemChangeEnabled(), setItemChangesEnabled(), itemChange() +*/ +void QGraphicsItem::setItemChangeEnabled(GraphicsItemChange change, bool enabled) +{ + if (enabled) { + d_ptr->itemChangesEnabled |= itemChangeBits[change]; + } else { + d_ptr->itemChangesEnabled &= itemChangeBits[change]; + } +} + +/*! + If \a enabled is true, all item change notifications are enabled; + otherwise, they are disabled. You can toggle individual notifications by + calling setItemChangeEnabled(). + + \sa itemChangeEnabled(), itemChange() +*/ +void QGraphicsItem::setItemChangesEnabled(bool enabled) +{ + d_ptr->itemChangesEnabled = enabled ? 0xffff : 0; } /*! @@ -1532,9 +1609,13 @@ QString QGraphicsItem::toolTip() const */ void QGraphicsItem::setToolTip(const QString &toolTip) { - const QVariant toolTipVariant(itemChange(ItemToolTipChange, toolTip)); - d_ptr->setExtra(QGraphicsItemPrivate::ExtraToolTip, toolTipVariant.toString()); - itemChange(ItemToolTipHasChanged, toolTipVariant); + bool notify = itemChangeEnabled(ItemToolTipChange); + QVariant toolTipVariant = toolTip; + if (notify) + toolTipVariant = itemChange(ItemToolTipChange, toolTipVariant); + d_ptr->setExtra(QGraphicsItemPrivate::ExtraToolTip, toolTipVariant); + if (notify) + itemChange(ItemToolTipHasChanged, toolTipVariant); } #endif // QT_NO_TOOLTIP @@ -1576,8 +1657,11 @@ QCursor QGraphicsItem::cursor() const */ void QGraphicsItem::setCursor(const QCursor &cursor) { - const QVariant cursorVariant(itemChange(ItemCursorChange, qVariantFromValue(cursor))); - d_ptr->setExtra(QGraphicsItemPrivate::ExtraCursor, qVariantValue(cursorVariant)); + bool notify = itemChangeEnabled(ItemCursorChange); + QVariant cursorVariant = qVariantFromValue(cursor); + if (notify) + cursorVariant = itemChange(ItemCursorChange, cursorVariant); + d_ptr->setExtra(QGraphicsItemPrivate::ExtraCursor, cursorVariant); d_ptr->hasCursor = 1; if (d_ptr->scene) { d_ptr->scene->d_func()->allItemsUseDefaultCursor = false; @@ -1596,7 +1680,8 @@ void QGraphicsItem::setCursor(const QCursor &cursor) } } } - itemChange(ItemCursorHasChanged, cursorVariant); + if (notify) + itemChange(ItemCursorHasChanged, cursorVariant); } /*! @@ -1693,10 +1778,12 @@ void QGraphicsItemPrivate::setVisibleHelper(bool newVisible, bool explicitly, bo if (parent && newVisible && !parent->d_ptr->visible) return; + // Notify + bool notify = q->itemChangeEnabled(QGraphicsItem::ItemVisibleChange); + if (notify) + newVisible = q_ptr->itemChange(QGraphicsItem::ItemVisibleChange, quint32(newVisible)).toBool(); + // Modify the property. - const QVariant newVisibleVariant(q_ptr->itemChange(QGraphicsItem::ItemVisibleChange, - quint32(newVisible))); - newVisible = newVisibleVariant.toBool(); if (visible == quint32(newVisible)) return; visible = newVisible; @@ -1763,7 +1850,8 @@ void QGraphicsItemPrivate::setVisibleHelper(bool newVisible, bool explicitly, bo } // Deliver post-change notification. - q_ptr->itemChange(QGraphicsItem::ItemVisibleHasChanged, newVisibleVariant); + if (notify) + q_ptr->itemChange(QGraphicsItem::ItemVisibleHasChanged, newVisible); } /*! @@ -1869,9 +1957,10 @@ void QGraphicsItemPrivate::setEnabledHelper(bool newEnabled, bool explicitly, bo } // Modify the property. - const QVariant newEnabledVariant(q_ptr->itemChange(QGraphicsItem::ItemEnabledChange, - quint32(newEnabled))); - enabled = newEnabledVariant.toBool(); + bool notify = q_ptr->itemChangeEnabled(QGraphicsItem::ItemEnabledChange); + if (notify) + newEnabled = q_ptr->itemChange(QGraphicsItem::ItemEnabledChange, quint32(newEnabled)).toBool(); + enabled = newEnabled; // Schedule redraw. if (update && scene) @@ -1883,7 +1972,8 @@ void QGraphicsItemPrivate::setEnabledHelper(bool newEnabled, bool explicitly, bo } // Deliver post-change notification. - q_ptr->itemChange(QGraphicsItem::ItemEnabledHasChanged, newEnabledVariant); + if (notify) + q_ptr->itemChange(QGraphicsItem::ItemEnabledHasChanged, newEnabled); } /*! @@ -1970,10 +2060,13 @@ void QGraphicsItem::setSelected(bool selected) selected = false; if (d_ptr->selected == selected) return; - const QVariant newSelectedVariant(itemChange(ItemSelectedChange, quint32(selected))); - bool newSelected = newSelectedVariant.toBool(); - if (d_ptr->selected == newSelected) - return; + bool notify = itemChangeEnabled(ItemSelectedChange); + bool newSelected = selected; + if (notify) { + newSelected = itemChange(ItemSelectedChange, quint32(selected)).toBool(); + if (d_ptr->selected == newSelected) + return; + } d_ptr->selected = newSelected; if (d_ptr->scene) { @@ -1990,7 +2083,8 @@ void QGraphicsItem::setSelected(bool selected) } // Deliver post-change notification. - itemChange(QGraphicsItem::ItemSelectedHasChanged, newSelectedVariant); + if (notify) + itemChange(QGraphicsItem::ItemSelectedHasChanged, newSelected); } /*! @@ -2056,13 +2150,12 @@ qreal QGraphicsItem::effectiveOpacity() const */ void QGraphicsItem::setOpacity(qreal opacity) { - // Notify change. -#ifndef QGRAPHICSITEM_NO_ITEMCHANGE - const QVariant newOpacityVariant(itemChange(ItemOpacityChange, double(opacity))); - qreal newOpacity = newOpacityVariant.toDouble(); -#else qreal newOpacity = opacity; -#endif + + // Notify + bool notify = itemChangeEnabled(ItemOpacityChange); + if (notify) + newOpacity = itemChange(ItemOpacityChange, double(newOpacity)).toDouble(); // Normalize. newOpacity = qBound(0.0, newOpacity, 1.0); @@ -2073,10 +2166,9 @@ void QGraphicsItem::setOpacity(qreal opacity) d_ptr->opacity = newOpacity; - // Notify change. -#ifndef QGRAPHICSITEM_NO_ITEMCHANGE - itemChange(ItemOpacityHasChanged, newOpacity); -#endif + // Notify + if (notify) + itemChange(ItemOpacityHasChanged, newOpacity); // Update. if (d_ptr->scene) @@ -2525,15 +2617,15 @@ void QGraphicsItemPrivate::setPosHelper(const QPointF &pos) if (this->pos == pos) return; - // Notify the item that the position is changing. -#ifndef QGRAPHICSITEM_NO_ITEMCHANGE - const QVariant newPosVariant(q->itemChange(QGraphicsItem::ItemPositionChange, pos)); - QPointF newPos = newPosVariant.toPointF(); - if (newPos == this->pos) - return; -#else QPointF newPos = pos; -#endif + + // Notify + bool notify = q->itemChangeEnabled(QGraphicsItem::ItemPositionChange); + if (notify) { + newPos = q->itemChange(QGraphicsItem::ItemPositionChange, pos).toPointF(); + if (newPos == this->pos) + return; + } // Update and repositition. inSetPosHelper = 1; @@ -2544,9 +2636,9 @@ void QGraphicsItemPrivate::setPosHelper(const QPointF &pos) dirtySceneTransform = 1; // Send post-notification. -#ifndef QGRAPHICSITEM_NO_ITEMCHANGE - q->itemChange(QGraphicsItem::ItemPositionHasChanged, newPosVariant); -#endif + if (notify) + q->itemChange(QGraphicsItem::ItemPositionHasChanged, newPos); + inSetPosHelper = 0; } @@ -2887,21 +2979,21 @@ QTransform QGraphicsItem::itemTransform(const QGraphicsItem *other, bool *ok) co */ void QGraphicsItem::setMatrix(const QMatrix &matrix, bool combine) { - if(!d_ptr->transform) + if (!d_ptr->transform) d_ptr->transform = new QTransform; QTransform newTransform(combine ? QTransform(matrix) * *d_ptr->transform : QTransform(matrix)); - if(*d_ptr->transform == newTransform) + if (*d_ptr->transform == newTransform) return; // Notify the item that the transformation matrix is changing. -#ifndef QGRAPHICSITEM_NO_ITEMCHANGE - const QVariant newTransformVariant(itemChange(ItemTransformChange, - qVariantFromValue(newTransform))); - newTransform = qVariantValue(newTransformVariant); - if (*d_ptr->transform == newTransform) - return; -#endif + bool notify = itemChangeEnabled(ItemMatrixChange); + if (notify) { + newTransform = QTransform(qVariantValue(itemChange(ItemMatrixChange, + qVariantFromValue(newTransform.toAffine())))); + if (*d_ptr->transform == newTransform) + return; + } // Update and set the new transformation. prepareGeometryChange(); @@ -2909,9 +3001,8 @@ void QGraphicsItem::setMatrix(const QMatrix &matrix, bool combine) d_ptr->dirtySceneTransform = 1; // Send post-notification. -#ifndef QGRAPHICSITEM_NO_ITEMCHANGE - itemChange(ItemTransformHasChanged, newTransformVariant); -#endif + if (notify) + itemChange(ItemTransformHasChanged, qVariantFromValue(newTransform)); } /*! @@ -2936,19 +3027,20 @@ void QGraphicsItem::setMatrix(const QMatrix &matrix, bool combine) */ void QGraphicsItem::setTransform(const QTransform &matrix, bool combine) { - if(!d_ptr->transform) + if (!d_ptr->transform) d_ptr->transform = new QTransform; QTransform newTransform(combine ? matrix * *d_ptr->transform : matrix); - if(*d_ptr->transform == newTransform) + if (*d_ptr->transform == newTransform) return; // Notify the item that the transformation matrix is changing. - const QVariant newTransformVariant(itemChange(ItemTransformChange, - qVariantFromValue(newTransform))); - newTransform = qVariantValue(newTransformVariant); - if (*d_ptr->transform == newTransform) - return; + bool notify = itemChangeEnabled(ItemTransformChange); + if (notify) { + newTransform = qVariantValue(itemChange(ItemTransformChange, qVariantFromValue(newTransform))); + if (*d_ptr->transform == newTransform) + return; + } // Update and set the new transformation. prepareGeometryChange(); @@ -2956,7 +3048,8 @@ void QGraphicsItem::setTransform(const QTransform &matrix, bool combine) d_ptr->dirtySceneTransform = 1; // Send post-notification. - itemChange(ItemTransformHasChanged, newTransformVariant); + if (notify) + itemChange(ItemTransformHasChanged, qVariantFromValue(newTransform)); } /*! @@ -3129,10 +3222,13 @@ qreal QGraphicsItem::zValue() const */ void QGraphicsItem::setZValue(qreal z) { - const QVariant newZVariant(itemChange(ItemZValueChange, double(z))); - qreal newZ = qreal(newZVariant.toDouble()); - if (newZ == d_ptr->z) - return; + bool notify = itemChangeEnabled(ItemZValueChange); + qreal newZ = z; + if (notify) { + newZ = itemChange(ItemZValueChange, double(z)).toDouble(); + if (newZ == d_ptr->z) + return; + } d_ptr->z = newZ; d_ptr->needSortChildren = 1; @@ -3143,7 +3239,8 @@ void QGraphicsItem::setZValue(qreal z) d_ptr->scene->d_func()->invalidateSortCache(); } - itemChange(ItemZValueHasChanged, newZVariant); + if (notify) + itemChange(ItemZValueHasChanged, newZ); } /*! diff --git a/src/gui/graphicsview/qgraphicsitem.h b/src/gui/graphicsview/qgraphicsitem.h index 737ea80..7c87176 100644 --- a/src/gui/graphicsview/qgraphicsitem.h +++ b/src/gui/graphicsview/qgraphicsitem.h @@ -129,6 +129,7 @@ public: ItemZValueHasChanged, ItemOpacityChange, ItemOpacityHasChanged + // NB! Don't forget to increase d_ptr->itemChangesEnabled when adding a new entry. }; enum CacheMode { @@ -165,6 +166,10 @@ public: void setFlag(GraphicsItemFlag flag, bool enabled = true); void setFlags(GraphicsItemFlags flags); + bool itemChangeEnabled(GraphicsItemChange change) const; + void setItemChangeEnabled(GraphicsItemChange change, bool enabled); + void setItemChangesEnabled(bool enabled); + CacheMode cacheMode() const; void setCacheMode(CacheMode mode, const QSize &cacheSize = QSize()); diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index b0b940b..2752056 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -147,6 +147,7 @@ public: dirtyChildrenBoundingRect(1), paintedViewBoundingRectsNeedRepaint(0), dirtySceneTransform(1), + itemChangesEnabled(0xffff), globalStackingOrder(-1), q_ptr(0) { @@ -396,7 +397,8 @@ public: quint32 dirtyChildrenBoundingRect : 1; quint32 paintedViewBoundingRectsNeedRepaint : 1; quint32 dirtySceneTransform : 1; - quint32 padding : 18; // feel free to use + quint32 itemChangesEnabled : 16; + quint32 padding : 3; // feel free to use // Optional stacking order int globalStackingOrder; diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index 8641fe2..96800a3 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -666,8 +666,10 @@ void QGraphicsScenePrivate::_q_polishItems() const QVariant booleanTrueVariant(true); foreach (QGraphicsItem *item, unpolishedItems) { if (!item->d_ptr->explicitlyHidden) { - item->itemChange(QGraphicsItem::ItemVisibleChange, booleanTrueVariant); - item->itemChange(QGraphicsItem::ItemVisibleHasChanged, booleanTrueVariant); + if (item->itemChangeEnabled(QGraphicsItem::ItemVisibleChange)) { + item->itemChange(QGraphicsItem::ItemVisibleChange, booleanTrueVariant); + item->itemChange(QGraphicsItem::ItemVisibleHasChanged, booleanTrueVariant); + } } if (item->isWidget()) { QEvent event(QEvent::Polish); @@ -2950,9 +2952,12 @@ void QGraphicsScene::addItem(QGraphicsItem *item) // Notify the item that its scene is changing, and allow the item to // react. - const QVariant newSceneVariant(item->itemChange(QGraphicsItem::ItemSceneChange, - qVariantFromValue(this))); - QGraphicsScene *targetScene = qVariantValue(newSceneVariant); + QGraphicsScene *targetScene = this; + bool notify = item->itemChangeEnabled(QGraphicsItem::ItemSceneChange); + if (notify) { + targetScene = qVariantValue(item->itemChange(QGraphicsItem::ItemSceneChange, + qVariantFromValue(this))); + } if (targetScene != this) { if (targetScene && item->scene() != targetScene) targetScene->addItem(item); @@ -3063,7 +3068,8 @@ void QGraphicsScene::addItem(QGraphicsItem *item) emit selectionChanged(); // Deliver post-change notification - item->itemChange(QGraphicsItem::ItemSceneHasChanged, newSceneVariant); + if (notify) + item->itemChange(QGraphicsItem::ItemSceneHasChanged, qVariantFromValue(targetScene)); } /*! @@ -3327,9 +3333,12 @@ void QGraphicsScene::removeItem(QGraphicsItem *item) // Notify the item that it's scene is changing to 0, allowing the item to // react. - const QVariant newSceneVariant(item->itemChange(QGraphicsItem::ItemSceneChange, - qVariantFromValue(0))); - QGraphicsScene *targetScene = qVariantValue(newSceneVariant); + QGraphicsScene *targetScene = 0; + bool notify = item->itemChangeEnabled(QGraphicsItem::ItemSceneChange); + if (notify) { + targetScene = qVariantValue(item->itemChange(QGraphicsItem::ItemSceneChange, + qVariantFromValue(0))); + } if (targetScene != 0 && targetScene != this) { targetScene->addItem(item); return; @@ -3425,7 +3434,8 @@ void QGraphicsScene::removeItem(QGraphicsItem *item) emit selectionChanged(); // Deliver post-change notification - item->itemChange(QGraphicsItem::ItemSceneHasChanged, newSceneVariant); + if (notify) + item->itemChange(QGraphicsItem::ItemSceneHasChanged, qVariantFromValue(targetScene)); } /*! -- cgit v0.12 From b6b0469e2d3aba2a163fab8c4b2fda4ab775b7f7 Mon Sep 17 00:00:00 2001 From: Andreas Aardal Hanssen Date: Wed, 3 Jun 2009 17:06:24 +0200 Subject: Add BSP tree support to the recursive drawing algorithm. The code looks ugly and needs to be refactored, but at least this reintroduces the BSP so the chip demo works fine again. --- src/gui/graphicsview/qgraphicsscene.cpp | 41 +++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index 96800a3..7a6c21c 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -5167,22 +5167,49 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * } // Find and sort children. - QList &children = item ? item->d_ptr->children : (topLevelItems ? *topLevelItems : this->topLevelItems); + QList tmp; + QList *children = 0; + if (item) { + children = &item->d_ptr->children; + } else if (topLevelItems) { + children = topLevelItems; + } else if (indexMethod == QGraphicsScene::NoIndex || !exposedRegion) { + children = &this->topLevelItems; + } else { + tmp = estimateItemsInRect(viewTransform.inverted().mapRect(exposedRegion->boundingRect())); + + QList tli; + for (int i = 0; i < tmp.size(); ++i) { + QGraphicsItem *it = tmp.at(i)->topLevelItem(); + if (!it->d_ptr->itemDiscovered) { + tli << it; + it->d_ptr->itemDiscovered = 1; + } + } + for (int i = 0; i < tli.size(); ++i) + tli.at(i)->d_ptr->itemDiscovered = 0; + + tmp = tli; + children = &tmp; + } + if (!dontDrawChildren) { if (item && item->d_ptr->needSortChildren) { item->d_ptr->needSortChildren = 0; - qStableSort(children.begin(), children.end(), qt_notclosestLeaf); + qStableSort(children->begin(), children->end(), qt_notclosestLeaf); } else if (!item && needSortTopLevelItems) { needSortTopLevelItems = false; - qStableSort(children.begin(), children.end(), qt_notclosestLeaf); + qStableSort(children->begin(), children->end(), qt_notclosestLeaf); + } else if (!item && children == &tmp) { + qStableSort(children->begin(), children->end(), qt_notclosestLeaf); } } // Draw children behind int i = 0; if (!dontDrawChildren) { - for (i = 0; i < children.size(); ++i) { - QGraphicsItem *child = children.at(i); + for (i = 0; i < children->size(); ++i) { + QGraphicsItem *child = children->at(i); if (wasDirtyParentSceneTransform) child->d_ptr->dirtySceneTransform = 1; if (!(child->d_ptr->flags & QGraphicsItem::ItemStacksBehindParent)) @@ -5213,8 +5240,8 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * // Draw children in front if (!dontDrawChildren) { - for (; i < children.size(); ++i) { - QGraphicsItem *child = children.at(i); + for (; i < children->size(); ++i) { + QGraphicsItem *child = children->at(i); if (wasDirtyParentSceneTransform) child->d_ptr->dirtySceneTransform = 1; drawSubtreeRecursive(child, painter, viewTransform, exposedRegion, -- cgit v0.12 From 5127105efd8f76721d7d9acf9681fd18e73760d8 Mon Sep 17 00:00:00 2001 From: Andreas Aardal Hanssen Date: Thu, 4 Jun 2009 15:16:40 +0200 Subject: Fix clipping bug, move code to avoid unintentional shadowing. The children variable tested for clipping was the wrong variable. This broke when the code was moved down as part of a previous cleanup change. Reviewed-by: bnilsen --- src/gui/graphicsview/qgraphicsscene.cpp | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index 7a6c21c..a137b06 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -5152,20 +5152,6 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * } } - bool childClip = (item && (item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape)); - bool dontDrawItem = !item || viewBoundingRect.isEmpty(); - bool dontDrawChildren = item && dontDrawItem && childClip; - childClip &= !dontDrawChildren & !children.isEmpty(); - if (item && item->d_ptr->flags & QGraphicsItem::ItemHasNoContents) - dontDrawItem = true; - - // Clip children. - if (childClip) { - painter->save(); - painter->setWorldTransform(transformTmp); - painter->setClipPath(item->shape(), Qt::IntersectClip); - } - // Find and sort children. QList tmp; QList *children = 0; @@ -5192,6 +5178,20 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * tmp = tli; children = &tmp; } + + bool childClip = (item && (item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape)); + bool dontDrawItem = !item || viewBoundingRect.isEmpty(); + bool dontDrawChildren = item && dontDrawItem && childClip; + childClip &= !dontDrawChildren & !children->isEmpty(); + if (item && item->d_ptr->flags & QGraphicsItem::ItemHasNoContents) + dontDrawItem = true; + + // Clip children. + if (childClip) { + painter->save(); + painter->setWorldTransform(transformTmp); + painter->setClipPath(item->shape(), Qt::IntersectClip); + } if (!dontDrawChildren) { if (item && item->d_ptr->needSortChildren) { -- cgit v0.12 From 2e8a236108f5b78c4d61a254f4097ccf271f90cb Mon Sep 17 00:00:00 2001 From: Andreas Aardal Hanssen Date: Thu, 4 Jun 2009 15:35:53 +0200 Subject: Ensure we can find and draw items whose size is (0x0). This removes a microoptimization we did to avoid processing items whose size was (0x0). Turns out an autotest started failing if we did this - we have to find and draw such items because they are commonly used to draw points (e.g., plot graphs). Reviewed-by: bnilsen --- src/gui/graphicsview/qgraphicsscene.cpp | 61 +++++++++++++++------------------ 1 file changed, 27 insertions(+), 34 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index a137b06..bb26bb6 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -297,13 +297,9 @@ static inline bool QRectF_intersects(const QRectF &s, const QRectF &r) static inline void _q_adjustRect(QRectF *rect) { Q_ASSERT(rect); - bool nullWidth = !rect->width(); - bool nullHeight = !rect->height(); - if (nullWidth && nullHeight) - return; - if (nullWidth) + if (!rect->width()) rect->adjust(-0.00001, 0, 0.00001, 0); - else if (nullHeight) + if (!rect->height()) rect->adjust(0, -0.00001, 0, 0.00001); } @@ -1413,33 +1409,26 @@ void QGraphicsScenePrivate::recursive_items_helper(QGraphicsItem *item, QRectF r if (item) { item->d_ptr->combineTransformFromParent(&transform, &viewTransform); + // ### This does not take the clip into account. QRectF brect = item->boundingRect(); - if (!brect.size().isNull()) { - // ### This does not take the clip into account. - _q_adjustRect(&brect); - - keep = true; - if (mode == Qt::ContainsItemShape || mode == Qt::ContainsItemBoundingRect) - keep = rect.contains(transform.mapRect(brect)); - else - keep = rect.intersects(transform.mapRect(brect)); - - if (keep && (mode == Qt::ContainsItemShape || mode == Qt::IntersectsItemShape)) { - QPainterPath rectPath; - rectPath.addRect(rect); - keep = item->collidesWithPath(transform.inverted().map(rectPath)); - } + _q_adjustRect(&brect); + + keep = true; + if (mode == Qt::ContainsItemShape || mode == Qt::ContainsItemBoundingRect) + keep = rect.contains(transform.mapRect(brect)); + else + keep = rect.intersects(transform.mapRect(brect)); + + if (keep && (mode == Qt::ContainsItemShape || mode == Qt::IntersectsItemShape)) { + QPainterPath rectPath; + rectPath.addRect(rect); + keep = item->collidesWithPath(transform.inverted().map(rectPath)); } } bool childClip = (item && (item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape)); bool dontProcessItem = !item || !keep; bool dontProcessChildren = item && dontProcessItem && childClip; - childClip &= !dontProcessChildren & !children.isEmpty(); - - // Clip. - if (childClip) - rect &= transform.map(item->shape()).controlPointRect(); // Find and sort children. QList &children = item ? item->d_ptr->children : const_cast(this)->topLevelItems; @@ -1453,6 +1442,12 @@ void QGraphicsScenePrivate::recursive_items_helper(QGraphicsItem *item, QRectF r } } + childClip &= !dontProcessChildren & !children.isEmpty(); + + // Clip. + if (childClip) + rect &= transform.map(item->shape()).controlPointRect(); + // Process children behind int i = 0; if (!dontProcessChildren) { @@ -5142,14 +5137,12 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * } QRectF brect = item->boundingRect(); - if (!brect.size().isNull()) { - // ### This does not take the clip into account. - _q_adjustRect(&brect); - viewBoundingRect = transformTmp.mapRect(brect).toRect().adjusted(-1, -1, 1, 1); - item->d_ptr->paintedViewBoundingRects.insert(widget, viewBoundingRect); - if (exposedRegion) - viewBoundingRect &= exposedRegion->boundingRect(); - } + // ### This does not take the clip into account. + _q_adjustRect(&brect); + viewBoundingRect = transformTmp.mapRect(brect).toRect().adjusted(-1, -1, 1, 1); + item->d_ptr->paintedViewBoundingRects.insert(widget, viewBoundingRect); + if (exposedRegion) + viewBoundingRect &= exposedRegion->boundingRect(); } // Find and sort children. -- cgit v0.12 From ba48a3fdf39a3db7a3d13ac15031c810454c6e25 Mon Sep 17 00:00:00 2001 From: Andreas Aardal Hanssen Date: Thu, 4 Jun 2009 15:59:25 +0200 Subject: Fix bug in QGraphicsItem::effectiveOpacity() caused by typo. See change 72842b2d, the patch misplaces 'p' and 'parent'. This fixes the tst_QGraphicsItem::opacity autotests. Reviewed-by: bnilsen --- src/gui/graphicsview/qgraphicsitem_p.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index 2752056..9be9310 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -296,10 +296,11 @@ public: // parent propagates to me, then combine my local opacity with my parent's // effective opacity into my effective opacity. if ((myFlags & QGraphicsItem::ItemIgnoresParentOpacity) - || (parentFlags & QGraphicsItem::ItemDoesntPropagateOpacityToChildren)) + || (parentFlags & QGraphicsItem::ItemDoesntPropagateOpacityToChildren)) { break; + } - o *= parent->d_ptr->opacity; + o *= p->d_ptr->opacity; p = p->d_ptr->parent; myFlags = parentFlags; } -- cgit v0.12 From 32c00c1d30eb275f44ba9d0bff4d6b6b05e9a5ba Mon Sep 17 00:00:00 2001 From: Andreas Aardal Hanssen Date: Thu, 4 Jun 2009 16:49:10 +0200 Subject: Fix rendering of items that ignore parent opacity. Test if the children ignore the parent's opacity if the current item's opacity is 0.0. If any of the children do ignore the parent then we must continue. Further optimizations are possible: if the item itself is transparent, then don't visit children that don't ignore parent opacity. Reviewed-by: bnilsen --- src/gui/graphicsview/qgraphicsscene.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index bb26bb6..c46ed68 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -5101,6 +5101,7 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * { // Calculate opacity. qreal opacity; + bool invisibleButChildIgnoresParentOpacity = false; if (item) { if (!item->d_ptr->visible) return; @@ -5112,8 +5113,11 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * } else { opacity = item->d_ptr->opacity; } - if (opacity == 0.0 && !(item->d_ptr->flags & QGraphicsItem::ItemDoesntPropagateOpacityToChildren)) - return; + if (opacity == 0.0 && !(item->d_ptr->flags & QGraphicsItem::ItemDoesntPropagateOpacityToChildren)) { + invisibleButChildIgnoresParentOpacity = !item->d_ptr->childrenCombineOpacity(); + if (!invisibleButChildIgnoresParentOpacity) + return; + } } else { opacity = parentOpacity; } @@ -5176,7 +5180,7 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * bool dontDrawItem = !item || viewBoundingRect.isEmpty(); bool dontDrawChildren = item && dontDrawItem && childClip; childClip &= !dontDrawChildren & !children->isEmpty(); - if (item && item->d_ptr->flags & QGraphicsItem::ItemHasNoContents) + if (item && (item->d_ptr->flags & QGraphicsItem::ItemHasNoContents) || invisibleButChildIgnoresParentOpacity) dontDrawItem = true; // Clip children. @@ -5201,6 +5205,8 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * // Draw children behind int i = 0; if (!dontDrawChildren) { + // ### Don't visit children that don't ignore parent opacity if this + // item is invisible. for (i = 0; i < children->size(); ++i) { QGraphicsItem *child = children->at(i); if (wasDirtyParentSceneTransform) @@ -5233,6 +5239,8 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * // Draw children in front if (!dontDrawChildren) { + // ### Don't visit children that don't ignore parent opacity if this + // item is invisible. for (; i < children->size(); ++i) { QGraphicsItem *child = children->at(i); if (wasDirtyParentSceneTransform) -- cgit v0.12 From 9eb253eed0ae75d1d32b5e738ead89434fc69837 Mon Sep 17 00:00:00 2001 From: Andreas Aardal Hanssen Date: Thu, 4 Jun 2009 17:07:58 +0200 Subject: Fix stacking order bug, ensure the dirty sort bits are set correctly. The code marked the item's own stacking order as dirty when changing its own Z value, the right thing is however to set the _parent's_ bit. Also added missing code for when the ItemStacksBehindParent flag was toggled. Reviewed-by: bnilsen --- src/gui/graphicsview/qgraphicsitem.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index 2eb5150..47a9ae2 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -1442,6 +1442,14 @@ void QGraphicsItem::setFlags(GraphicsItemFlags flags) d_ptr->updateAncestorFlag(ItemIgnoresTransformations); } + if ((flags & ItemStacksBehindParent) != (oldFlags & ItemStacksBehindParent)) { + // Ensure child item sorting is up to date when toggling this flag. + if (d_ptr->parent) + d_ptr->parent->d_ptr->needSortChildren = 1; + else if (d_ptr->scene) + d_ptr->scene->d_func()->needSortTopLevelItems = 1; + } + if (d_ptr->scene) { d_ptr->scene->d_func()->markDirty(this, QRectF(), /*invalidateChildren=*/true, @@ -3230,7 +3238,10 @@ void QGraphicsItem::setZValue(qreal z) return; } d_ptr->z = newZ; - d_ptr->needSortChildren = 1; + if (d_ptr->parent) + d_ptr->parent->d_ptr->needSortChildren = 1; + else if (d_ptr->scene) + d_ptr->scene->d_func()->needSortTopLevelItems = 1; if (d_ptr->scene) { d_ptr->scene->d_func()->markDirty(this, QRectF(), /*invalidateChildren=*/true); -- cgit v0.12 From a47b632971068001d56471a9cb78ad983c4a9fee Mon Sep 17 00:00:00 2001 From: Andreas Aardal Hanssen Date: Thu, 4 Jun 2009 17:12:42 +0200 Subject: Ensure this test goes via QGraphicsScene::drawItems(). Enable QGraphicsView::IndirectPainting to make sure it detects which items are drawn. --- tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp index 9cfd897..427ecf3 100644 --- a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp +++ b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp @@ -5874,6 +5874,7 @@ void tst_QGraphicsItem::nestedClipping() l3->setData(0, "l3"); QGraphicsView view(&scene); + view.setOptimizationFlag(QGraphicsView::IndirectPainting); view.show(); #ifdef Q_WS_X11 qt_x11_wait_for_window_manager(&view); -- cgit v0.12 From 4f3a8e82fd6b328a06990517648f0d46c50ff41e Mon Sep 17 00:00:00 2001 From: Andreas Aardal Hanssen Date: Thu, 4 Jun 2009 17:26:57 +0200 Subject: Ensure we pass the intersect mode when checking item collisions. This fixes one of two failures in tst_QGraphicsScene::items_QRectF_2. The other seems unrelated. --- src/gui/graphicsview/qgraphicsscene.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index c46ed68..6a79dde 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -1422,7 +1422,7 @@ void QGraphicsScenePrivate::recursive_items_helper(QGraphicsItem *item, QRectF r if (keep && (mode == Qt::ContainsItemShape || mode == Qt::IntersectsItemShape)) { QPainterPath rectPath; rectPath.addRect(rect); - keep = item->collidesWithPath(transform.inverted().map(rectPath)); + keep = item->collidesWithPath(transform.inverted().map(rectPath), mode); } } -- cgit v0.12 From 98f197d1a11c3dd13959967534b1dba7eea479ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Nilsen?= Date: Thu, 4 Jun 2009 11:56:40 +0200 Subject: Avoid falling in the else case when there are no views. Partially fixes tst_QGraphicsScene::update failure. --- src/gui/graphicsview/qgraphicsscene.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index 6a79dde..df3153f 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -601,7 +601,7 @@ void QGraphicsScenePrivate::_q_emitUpdated() // the optimization that items send updates directly to the views, but it // needs to happen in order to keep compatibility with the behavior from // Qt 4.4 and backward. - if (!views.isEmpty() && (connectedSignals & changedSignalMask)) { + if (connectedSignals & changedSignalMask) { for (int i = 0; i < views.size(); ++i) { QGraphicsView *view = views.at(i); if (!view->d_func()->connectedToScene) { -- cgit v0.12 From ad92e095ea34dda9d099fae30340a8fbb4c5380a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Nilsen?= Date: Thu, 4 Jun 2009 17:31:47 +0200 Subject: Compatibility fix for QGraphicsScene::sceneRectChanged()/sceneRect(). We have to keep the growingItemsBoundingRect up-to-date if there's no scene rect. The only difference now is that sceneRectChanged will not be emitted before entering the event-loop, but the documentation only states it'll be emitted when the scene rect changes, so we consider it harmless. Makes tst_QGraphicsView::sceneRect_growing and tst_QGrahicsScene::sceneRect happy. Reviewed-by: Andreas --- src/gui/graphicsview/qgraphicsitem.cpp | 1 + src/gui/graphicsview/qgraphicsitem_p.h | 4 ++- src/gui/graphicsview/qgraphicsscene.cpp | 33 +++++++++++++++++------- src/gui/graphicsview/qgraphicsscene_p.h | 5 +++- tests/auto/qgraphicsscene/tst_qgraphicsscene.cpp | 2 ++ 5 files changed, 34 insertions(+), 11 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index 47a9ae2..807ee06 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -5977,6 +5977,7 @@ void QGraphicsItem::removeFromIndex() void QGraphicsItem::prepareGeometryChange() { if (d_ptr->scene) { + d_ptr->geometryChanged = 1; d_ptr->paintedViewBoundingRectsNeedRepaint = 1; d_ptr->scene->d_func()->markDirty(this, QRectF(), /*invalidateChildren=*/true, diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index 9be9310..d884b16 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -148,6 +148,7 @@ public: paintedViewBoundingRectsNeedRepaint(0), dirtySceneTransform(1), itemChangesEnabled(0xffff), + geometryChanged(0), globalStackingOrder(-1), q_ptr(0) { @@ -399,7 +400,8 @@ public: quint32 paintedViewBoundingRectsNeedRepaint : 1; quint32 dirtySceneTransform : 1; quint32 itemChangesEnabled : 16; - quint32 padding : 3; // feel free to use + quint32 geometryChanged : 1; + quint32 padding : 2; // feel free to use // Optional stacking order int globalStackingOrder; diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index df3153f..c738f80 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -39,7 +39,6 @@ ** ****************************************************************************/ -static const int QGRAPHICSSCENE_INDEXTIMER_TIMEOUT = 2000; /*! \class QGraphicsScene @@ -682,7 +681,11 @@ void QGraphicsScenePrivate::_q_processDirtyItems() if (updateAll) return; + const QRectF oldGrowingItemsBoundingRect = growingItemsBoundingRect; processDirtyItemsRecursive(0); + if (!hasSceneRect && oldGrowingItemsBoundingRect != growingItemsBoundingRect) + emit q_func()->sceneRectChanged(growingItemsBoundingRect); + for (int i = 0; i < views.size(); ++i) views.at(i)->d_func()->processPendingUpdates(); } @@ -808,13 +811,13 @@ void QGraphicsScenePrivate::purgeRemovedItems() Starts or restarts the timer used for reindexing unindexed items. */ -void QGraphicsScenePrivate::startIndexTimer() +void QGraphicsScenePrivate::startIndexTimer(int interval) { Q_Q(QGraphicsScene); if (indexTimerId) { restartIndexTimer = true; } else { - indexTimerId = q->startTimer(QGRAPHICSSCENE_INDEXTIMER_TIMEOUT); + indexTimerId = q->startTimer(interval); } } @@ -2982,7 +2985,7 @@ void QGraphicsScene::addItem(QGraphicsItem *item) // a temporary list and schedule an indexing for later. d->unindexedItems << item; item->d_func()->index = -1; - d->startIndexTimer(); + d->startIndexTimer(0); // Add to list of toplevels if this item is a toplevel. if (!item->d_ptr->parent) @@ -5315,16 +5318,27 @@ void QGraphicsScenePrivate::processDirtyItemsRecursive(QGraphicsItem *item, bool // Process item. if (item && (item->d_ptr->dirty || item->d_ptr->paintedViewBoundingRectsNeedRepaint)) { const bool useCompatUpdate = views.isEmpty() || (connectedSignals & changedSignalMask); - if (useCompatUpdate && !item->d_ptr->itemIsUntransformable() - && qFuzzyIsNull(item->boundingRegionGranularity())) { + const bool untransformableItem = item->d_ptr->itemIsUntransformable(); + const QRectF itemBoundingRect = item->boundingRect(); + + if (item->d_ptr->geometryChanged) { + // Update growingItemsBoundingRect. + if (!hasSceneRect) { + QRectF itemSceneBoundingRect = item->d_ptr->sceneTransform.mapRect(itemBoundingRect); + _q_adjustRect(&itemSceneBoundingRect); + growingItemsBoundingRect |= itemSceneBoundingRect; + } + item->d_ptr->geometryChanged = 0; + } + + if (useCompatUpdate && !untransformableItem && qFuzzyIsNull(item->boundingRegionGranularity())) { // This block of code is kept for compatibility. Since 4.5, by default // QGraphicsView does not connect the signal and we use the below // method of delivering updates. - q->update(item->sceneBoundingRect()); + q->update(item->d_ptr->sceneTransform.mapRect(itemBoundingRect)); } else { QRectF dirtyRect; bool uninitializedDirtyRect = true; - const bool untransformableItem = item->d_ptr->itemIsUntransformable(); for (int j = 0; j < views.size(); ++j) { QGraphicsView *view = views.at(j); @@ -5349,7 +5363,8 @@ void QGraphicsScenePrivate::processDirtyItemsRecursive(QGraphicsItem *item, bool continue; if (uninitializedDirtyRect) { - dirtyRect = adjustedItemBoundingRect(item); + dirtyRect = itemBoundingRect; + _q_adjustRect(&dirtyRect); if (!item->d_ptr->fullUpdatePending) { _q_adjustRect(&item->d_ptr->needsRepaint); dirtyRect &= item->d_ptr->needsRepaint; diff --git a/src/gui/graphicsview/qgraphicsscene_p.h b/src/gui/graphicsview/qgraphicsscene_p.h index f4964f2..fd7decf 100644 --- a/src/gui/graphicsview/qgraphicsscene_p.h +++ b/src/gui/graphicsview/qgraphicsscene_p.h @@ -71,6 +71,8 @@ #include #include +static const int QGRAPHICSSCENE_INDEXTIMER_TIMEOUT = 2000; + QT_BEGIN_NAMESPACE class QGraphicsView; @@ -138,7 +140,7 @@ public: int indexTimerId; bool restartIndexTimer; - void startIndexTimer(); + void startIndexTimer(int interval = QGRAPHICSSCENE_INDEXTIMER_TIMEOUT); bool stickyFocus; bool hasFocus; @@ -270,6 +272,7 @@ public: Q_ASSERT(item); item->d_ptr->dirty = 0; item->d_ptr->paintedViewBoundingRectsNeedRepaint = 0; + item->d_ptr->geometryChanged = 0; item->d_ptr->dirtyChildren = 0; item->d_ptr->needsRepaint = QRectF(); item->d_ptr->allChildrenDirty = 0; diff --git a/tests/auto/qgraphicsscene/tst_qgraphicsscene.cpp b/tests/auto/qgraphicsscene/tst_qgraphicsscene.cpp index 23d7a94..9f93ae0 100644 --- a/tests/auto/qgraphicsscene/tst_qgraphicsscene.cpp +++ b/tests/auto/qgraphicsscene/tst_qgraphicsscene.cpp @@ -274,7 +274,9 @@ void tst_QGraphicsScene::sceneRect() QCOMPARE(scene.sceneRect(), QRectF()); QGraphicsItem *item = scene.addRect(QRectF(0, 0, 10, 10)); + qApp->processEvents(); item->setPos(-5, -5); + qApp->processEvents(); QCOMPARE(scene.itemAt(0, 0), item); QCOMPARE(scene.itemAt(10, 10), (QGraphicsItem *)0); -- cgit v0.12 From ed0b10aff5d0afb7e8165dbf9b14f30cfd73e3ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Nilsen?= Date: Thu, 4 Jun 2009 18:06:24 +0200 Subject: Make sure we reset the updateAll variable correctly. Makes tst_QGraphicsScene::update happy. --- src/gui/graphicsview/qgraphicsscene.cpp | 1 + tests/auto/qgraphicsscene/tst_qgraphicsscene.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index c738f80..4578bd4 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -610,6 +610,7 @@ void QGraphicsScenePrivate::_q_emitUpdated() } } } else { + updateAll = false; for (int i = 0; i < views.size(); ++i) views.at(i)->d_func()->processPendingUpdates(); return; diff --git a/tests/auto/qgraphicsscene/tst_qgraphicsscene.cpp b/tests/auto/qgraphicsscene/tst_qgraphicsscene.cpp index 9f93ae0..8bb9122 100644 --- a/tests/auto/qgraphicsscene/tst_qgraphicsscene.cpp +++ b/tests/auto/qgraphicsscene/tst_qgraphicsscene.cpp @@ -2715,6 +2715,7 @@ void tst_QGraphicsScene::update() QGraphicsRectItem *rect = new QGraphicsRectItem(0, 0, 100, 100); scene.addItem(rect); + qApp->processEvents(); rect->setPos(-100, -100); // This function forces indexing -- cgit v0.12 From 9def469f9f83087fab9cb65c0200f2e6059519ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Nilsen?= Date: Thu, 4 Jun 2009 19:32:19 +0200 Subject: Compatibility fix for QGraphicsScene::changed signal. Makes tst_QGraphicsScene::changedSignal and tst_QGraphicsItem::setMatrix happy. --- src/gui/graphicsview/qgraphicsitem.cpp | 17 ++++++++++++++--- src/gui/graphicsview/qgraphicsscene.cpp | 8 ++++++++ 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index 807ee06..a2d885b 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -5979,10 +5979,21 @@ void QGraphicsItem::prepareGeometryChange() if (d_ptr->scene) { d_ptr->geometryChanged = 1; d_ptr->paintedViewBoundingRectsNeedRepaint = 1; - d_ptr->scene->d_func()->markDirty(this, QRectF(), - /*invalidateChildren=*/true, - /*maybeDirtyClipPath=*/!d_ptr->inSetPosHelper); + QGraphicsScenePrivate *scenePrivate = d_ptr->scene->d_func(); + scenePrivate->markDirty(this, QRectF(), + /*invalidateChildren=*/true, + /*maybeDirtyClipPath=*/!d_ptr->inSetPosHelper); + + // For compatibility reasons, we have to update the item's old geometry + // if someone is connected to the changed signal or the scene has no views. + // Note that this has to be done *after* markDirty to ensure that + // _q_processDirtyItems is called before _q_emitUpdated. + if ((scenePrivate->connectedSignals & scenePrivate->changedSignalMask) + || scenePrivate->views.isEmpty()) { + d_ptr->scene->update(sceneTransform().mapRect(boundingRect())); + } + scenePrivate->removeFromIndex(this); } diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index 4578bd4..c7a41d6 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -682,6 +682,7 @@ void QGraphicsScenePrivate::_q_processDirtyItems() if (updateAll) return; + const bool wasPendingSceneUpdate = calledEmitUpdated; const QRectF oldGrowingItemsBoundingRect = growingItemsBoundingRect; processDirtyItemsRecursive(0); if (!hasSceneRect && oldGrowingItemsBoundingRect != growingItemsBoundingRect) @@ -689,6 +690,13 @@ void QGraphicsScenePrivate::_q_processDirtyItems() for (int i = 0; i < views.size(); ++i) views.at(i)->d_func()->processPendingUpdates(); + + if (!wasPendingSceneUpdate && calledEmitUpdated) { + // We did a compatibility QGraphicsScene::update in processDirtyItemsRecursive + // and we cannot wait for the control to reach the eventloop before the + // changed signal is emitted, so we emit it now. + _q_emitUpdated(); + } } /*! -- cgit v0.12 From f1ada923f7bbe8724d9a9d6a6b391a92c514c440 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Nilsen?= Date: Thu, 4 Jun 2009 19:51:41 +0200 Subject: Discard updates outside the bounding rect. Makes tst_QGraphicsItem::cacheMode happy. --- 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 a2d885b..80ad19d 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -4168,7 +4168,7 @@ void QGraphicsItem::update(const QRectF &rect) } if (d_ptr->scene) - d_ptr->scene->d_func()->markDirty(this); + d_ptr->scene->d_func()->markDirty(this, rect); } /*! diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index c7a41d6..e5c65d1 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -5381,6 +5381,9 @@ void QGraphicsScenePrivate::processDirtyItemsRecursive(QGraphicsItem *item, bool uninitializedDirtyRect = false; } + if (dirtyRect.isEmpty()) + continue; // Discard updates outside the bounding rect. + QTransform deviceTransform = item->d_ptr->sceneTransform; if (view->isTransformed()) { if (!untransformableItem) -- cgit v0.12 From 4af92dcf716ee3c2fc4673aadd07fde19b7bffed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Nilsen?= Date: Thu, 4 Jun 2009 19:57:04 +0200 Subject: Make sure the dirty state of an item is reset when removed from the scene. Makes tst_QGraphicsItem::paint happy. --- src/gui/graphicsview/qgraphicsscene.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index e5c65d1..eaf00a0 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -758,6 +758,7 @@ void QGraphicsScenePrivate::_q_removeItemLater(QGraphicsItem *item) cachedItemsUnderMouse.removeAll(item); unpolishedItems.removeAll(item); pendingUpdateItems.removeAll(item); + resetDirtyItem(item); //We remove all references of item from the sceneEventFilter arrays QMultiMap::iterator iterator = sceneEventFilters.begin(); @@ -3408,6 +3409,7 @@ void QGraphicsScene::removeItem(QGraphicsItem *item) d->pendingUpdateItems.removeAll(item); d->cachedItemsUnderMouse.removeAll(item); d->unpolishedItems.removeAll(item); + d->resetDirtyItem(item); //We remove all references of item from the sceneEventFilter arrays QMultiMap::iterator iterator = d->sceneEventFilters.begin(); -- cgit v0.12 From 9aa44bff88f377f056eafe5d9f24c88d81f477e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Nilsen?= Date: Thu, 4 Jun 2009 20:58:34 +0200 Subject: Removes odd artifact in the chip demo. Calling repaint() instead of update() is bad when having multiple views (which GV perfectly supports). The result is that e.g. when moving a chip in the chip demo, there's a visible lag between each view. It can also be a performance killer on QWS, where the surface is locked for each repaint(). Instead of calling repaint() we call update() as before, but we also make sure the updates are processed immediately. --- src/gui/graphicsview/qgraphicsscene.cpp | 9 +++++++++ src/gui/graphicsview/qgraphicsview.cpp | 6 +++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index eaf00a0..4b54c08 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -697,6 +697,15 @@ void QGraphicsScenePrivate::_q_processDirtyItems() // changed signal is emitted, so we emit it now. _q_emitUpdated(); } + + // Immediately dispatch all pending update requests on the views. + for (int i = 0; i < views.size(); ++i) { + QWidget *viewport = views.at(i)->d_func()->viewport; + if (qt_widget_private(viewport)->paintOnScreen()) + QCoreApplication::sendPostedEvents(viewport, QEvent::UpdateRequest); + else + QCoreApplication::sendPostedEvents(viewport->window(), QEvent::UpdateRequest); + } } /*! diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp index c91e0d1..87b5e3f 100644 --- a/src/gui/graphicsview/qgraphicsview.cpp +++ b/src/gui/graphicsview/qgraphicsview.cpp @@ -814,11 +814,11 @@ void QGraphicsViewPrivate::processPendingUpdates() if (viewportUpdateMode == QGraphicsView::BoundingRectViewportUpdate) { if (optimizationFlags & QGraphicsView::DontAdjustForAntialiasing) - viewport->repaint(dirtyBoundingRect); + viewport->update(dirtyBoundingRect); else - viewport->repaint(dirtyBoundingRect.adjusted(-2, -2, 2, 2)); + viewport->update(dirtyBoundingRect.adjusted(-2, -2, 2, 2)); } else { - viewport->repaint(dirtyRegion); // Already adjusted in updateRect/Region. + viewport->update(dirtyRegion); // Already adjusted in updateRect/Region. } dirtyBoundingRect = QRect(); -- cgit v0.12 From 5ab06593a1ed4c050d19f734737a50078b0fbb52 Mon Sep 17 00:00:00 2001 From: Andreas Aardal Hanssen Date: Fri, 5 Jun 2009 09:00:21 +0200 Subject: Fix tst_QGraphicsView::acceptMousePressEvent (by entering event loop). This is necessary after we made the sceneRect grow lazily when it's not assigned. --- tests/auto/qgraphicsview/tst_qgraphicsview.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/auto/qgraphicsview/tst_qgraphicsview.cpp b/tests/auto/qgraphicsview/tst_qgraphicsview.cpp index 8e490ad..718c8d6 100644 --- a/tests/auto/qgraphicsview/tst_qgraphicsview.cpp +++ b/tests/auto/qgraphicsview/tst_qgraphicsview.cpp @@ -2525,6 +2525,8 @@ void tst_QGraphicsView::acceptMousePressEvent() scene.addRect(0, 0, 2000, 2000)->setFlag(QGraphicsItem::ItemIsMovable); + qApp->processEvents(); // ensure scene rect is updated + QApplication::sendEvent(view.viewport(), &event); QVERIFY(view.accepted); } -- cgit v0.12 From 1c0599289a3da43b0a7cdb38eebe05d45f69ad9c Mon Sep 17 00:00:00 2001 From: Andreas Aardal Hanssen Date: Fri, 5 Jun 2009 10:11:05 +0200 Subject: Fix tst_QGraphicsView::cursor2() - sorting bug when using BSP tree. Make sure we don't claim that we have sorted all toplevel items when we are using the BSP tree, as when painting we have only actually sorted a subset of the elements. --- src/gui/graphicsview/qgraphicsscene.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index 4b54c08..6c78ca9 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -5217,11 +5217,11 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * if (item && item->d_ptr->needSortChildren) { item->d_ptr->needSortChildren = 0; qStableSort(children->begin(), children->end(), qt_notclosestLeaf); + } else if (!item && children == &tmp) { + qStableSort(children->begin(), children->end(), qt_notclosestLeaf); } else if (!item && needSortTopLevelItems) { needSortTopLevelItems = false; qStableSort(children->begin(), children->end(), qt_notclosestLeaf); - } else if (!item && children == &tmp) { - qStableSort(children->begin(), children->end(), qt_notclosestLeaf); } } -- cgit v0.12 From a10f1c955f9cbf54909ce2264279efa9d0423ecd Mon Sep 17 00:00:00 2001 From: Andreas Aardal Hanssen Date: Fri, 5 Jun 2009 10:23:37 +0200 Subject: Fix tst_QGraphicsScene::itemIndexMethod(), typo in estimateItemsInRect() Don't skip all indexed items that aren't transparent ;-). --- src/gui/graphicsview/qgraphicsscene.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index 6c78ca9..49ffb32 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -422,7 +422,7 @@ QList QGraphicsScenePrivate::estimateItemsInRect(const QRectF & if (QGraphicsItem *item = indexedItems.at(i)) { if (item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren) continue; - if (item->d_ptr->visible && item->d_ptr->isFullyTransparent()) + if (item->d_ptr->visible && !item->d_ptr->isFullyTransparent()) itemsInRect << item; } } -- cgit v0.12 From b7b0f7250dcf07a4da5d80ccc48accb156f25092 Mon Sep 17 00:00:00 2001 From: Andreas Aardal Hanssen Date: Fri, 5 Jun 2009 10:41:22 +0200 Subject: Fix tst_QGraphicsScene::items_QRectF_2(), an intersection bug. The recursive items function didn't contain the special case check for when the source and target rectangle are identical. --- src/gui/graphicsview/qgraphicsscene.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index 49ffb32..8958e1b 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -1437,7 +1437,7 @@ void QGraphicsScenePrivate::recursive_items_helper(QGraphicsItem *item, QRectF r keep = true; if (mode == Qt::ContainsItemShape || mode == Qt::ContainsItemBoundingRect) - keep = rect.contains(transform.mapRect(brect)); + keep = rect.contains(transform.mapRect(brect)) && rect != brect; else keep = rect.intersects(transform.mapRect(brect)); -- cgit v0.12 From f31b4a7163cee11c306e9f4fcaab094d9c38cb68 Mon Sep 17 00:00:00 2001 From: Andreas Aardal Hanssen Date: Fri, 5 Jun 2009 11:02:46 +0200 Subject: Fix interaction with QGraphicsWidgets that are a window. Use itemCollidesWithPath, the helper function. --- src/gui/graphicsview/qgraphicsscene.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index 8958e1b..de9d865 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -1444,7 +1444,7 @@ void QGraphicsScenePrivate::recursive_items_helper(QGraphicsItem *item, QRectF r if (keep && (mode == Qt::ContainsItemShape || mode == Qt::IntersectsItemShape)) { QPainterPath rectPath; rectPath.addRect(rect); - keep = item->collidesWithPath(transform.inverted().map(rectPath), mode); + keep = itemCollidesWithPath(item, transform.inverted().map(rectPath), mode); } } -- cgit v0.12 From e83cc0aca3bab0d37c4d0679319017f4cfeacfe0 Mon Sep 17 00:00:00 2001 From: Alexis Menard Date: Fri, 5 Jun 2009 12:54:04 +0200 Subject: Fix warning. --- src/gui/graphicsview/qgraphicsscene.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index de9d865..7bfc032 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -5202,8 +5202,8 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * bool childClip = (item && (item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape)); bool dontDrawItem = !item || viewBoundingRect.isEmpty(); bool dontDrawChildren = item && dontDrawItem && childClip; - childClip &= !dontDrawChildren & !children->isEmpty(); - if (item && (item->d_ptr->flags & QGraphicsItem::ItemHasNoContents) || invisibleButChildIgnoresParentOpacity) + childClip &= !dontDrawChildren && !children->isEmpty(); + if (item && ((item->d_ptr->flags & QGraphicsItem::ItemHasNoContents) || invisibleButChildIgnoresParentOpacity)) dontDrawItem = true; // Clip children. -- cgit v0.12 From 9cafd6bcf6f91c027904c998a0dd536feac8d4e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Nilsen?= Date: Mon, 8 Jun 2009 10:55:48 +0200 Subject: Child items leave traces when moving an ancestor item. The problem was that we only marked the painted view bounding rect of the moved item as dirty. We also have to mark its children. --- src/gui/graphicsview/qgraphicsscene.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index 7bfc032..caf9309 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -5336,6 +5336,7 @@ void QGraphicsScenePrivate::processDirtyItemsRecursive(QGraphicsItem *item, bool } // Process item. + bool wasDirtyParentViewBoundingRects = false; if (item && (item->d_ptr->dirty || item->d_ptr->paintedViewBoundingRectsNeedRepaint)) { const bool useCompatUpdate = views.isEmpty() || (connectedSignals & changedSignalMask); const bool untransformableItem = item->d_ptr->itemIsUntransformable(); @@ -5376,8 +5377,10 @@ void QGraphicsScenePrivate::processDirtyItemsRecursive(QGraphicsItem *item, bool break; } - if (item->d_ptr->paintedViewBoundingRectsNeedRepaint) + if (item->d_ptr->paintedViewBoundingRectsNeedRepaint) { + wasDirtyParentViewBoundingRects = true; viewPrivate->updateRect(item->d_ptr->paintedViewBoundingRects.value(viewPrivate->viewport)); + } if (!item->d_ptr->dirty) continue; @@ -5422,6 +5425,8 @@ void QGraphicsScenePrivate::processDirtyItemsRecursive(QGraphicsItem *item, bool QGraphicsItem *child = children->at(i); if (wasDirtyParentSceneTransform) child->d_ptr->dirtySceneTransform = 1; + if (wasDirtyParentViewBoundingRects) + child->d_ptr->paintedViewBoundingRectsNeedRepaint = 1; if (allChildrenDirty) { child->d_ptr->dirty = 1; -- cgit v0.12 From 0095e40b2efc0c43c0d908bb5b9828619bc087e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Nilsen?= Date: Mon, 8 Jun 2009 13:09:14 +0200 Subject: QGraphicsItem discard updates when it shouldn't. Once a _q_processDirtyItems call is queued, it means we at least have one item that is marked as dirty and we must reset it when the _q_processDirtyItems slot is called. The problem however, was that we didn't reset the item's dirty state if a full scene update occurred in between, i.e. item->update(); scene.update(); We don't have to calculate the item's dirty rect if a full scene update occurs in between, but we still have to reset its state. Auto-test included. --- src/gui/graphicsview/qgraphicsscene.cpp | 13 ++++++------ src/gui/graphicsview/qgraphicsview.cpp | 1 + tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp | 28 ++++++++++++++++++++++++++ 3 files changed, 36 insertions(+), 6 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index caf9309..ad392b0 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -679,19 +679,19 @@ void QGraphicsScenePrivate::_q_processDirtyItems() { processDirtyItemsEmitted = false; - if (updateAll) - return; - const bool wasPendingSceneUpdate = calledEmitUpdated; const QRectF oldGrowingItemsBoundingRect = growingItemsBoundingRect; processDirtyItemsRecursive(0); if (!hasSceneRect && oldGrowingItemsBoundingRect != growingItemsBoundingRect) emit q_func()->sceneRectChanged(growingItemsBoundingRect); + if (wasPendingSceneUpdate) + return; + for (int i = 0; i < views.size(); ++i) views.at(i)->d_func()->processPendingUpdates(); - if (!wasPendingSceneUpdate && calledEmitUpdated) { + if (calledEmitUpdated) { // We did a compatibility QGraphicsScene::update in processDirtyItemsRecursive // and we cannot wait for the control to reach the eventloop before the // changed signal is emitted, so we emit it now. @@ -5322,7 +5322,6 @@ void QGraphicsScenePrivate::markDirty(QGraphicsItem *item, const QRectF &rect, b void QGraphicsScenePrivate::processDirtyItemsRecursive(QGraphicsItem *item, bool dirtyAncestorContainsChildren) { - Q_ASSERT(!item || item->d_ptr->dirty || item->d_ptr->dirtyChildren); Q_Q(QGraphicsScene); // Calculate the full scene transform for this item. @@ -5438,13 +5437,15 @@ void QGraphicsScenePrivate::processDirtyItemsRecursive(QGraphicsItem *item, bool continue; } - if (dirtyAncestorContainsChildren) { + if (dirtyAncestorContainsChildren || updateAll) { // No need to process this child's dirty rect, hence reset the dirty state. // However, we have to continue the recursion because it might have a dirty // view bounding rect that needs repaint. We also have to reset the dirty // state of its descendants. child->d_ptr->dirty = 0; child->d_ptr->fullUpdatePending = 0; + if (updateAll) + child->d_ptr->paintedViewBoundingRectsNeedRepaint = 0; } processDirtyItemsRecursive(child, dirtyAncestorContainsChildren); diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp index 87b5e3f..a9fc563 100644 --- a/src/gui/graphicsview/qgraphicsview.cpp +++ b/src/gui/graphicsview/qgraphicsview.cpp @@ -2496,6 +2496,7 @@ void QGraphicsView::updateScene(const QList &rects) for (int i = 0; i < dirtyRects.size(); ++i) dirtyViewportRects += dirtyRects.at(i); d->dirtyRegion = QRegion(); + d->dirtyBoundingRect = QRect(); bool fullUpdate = !d->accelerateScrolling || d->viewportUpdateMode == QGraphicsView::FullViewportUpdate; bool boundingRectUpdate = (d->viewportUpdateMode == QGraphicsView::BoundingRectViewportUpdate) diff --git a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp index 427ecf3..5b297f6 100644 --- a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp +++ b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp @@ -219,6 +219,7 @@ private slots: void updateCachedItemAfterMove(); void deviceTransform_data(); void deviceTransform(); + void update(); // task specific tests below me void task141694_textItemEnsureVisible(); @@ -6427,5 +6428,32 @@ void tst_QGraphicsItem::deviceTransform() QCOMPARE(rect3->deviceTransform(deviceX).map(QPointF(50, 50)), mapResult3); } +void tst_QGraphicsItem::update() +{ + QGraphicsScene scene; + QGraphicsView view(&scene); + view.show(); +#ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(&view); +#endif + QTest::qWait(100); + + EventTester *item = new EventTester; + scene.addItem(item); + QTest::qWait(100); // Make sure all pending updates are processed. + item->repaints = 0; + + item->update(); // Item marked as dirty + scene.update(); // Entire scene marked as dirty + qApp->processEvents(); + QCOMPARE(item->repaints, 1); + + // Make sure the dirty state from the previous update is reset so that + // the item don't think it is already dirty and discards this update. + item->update(); + qApp->processEvents(); + QCOMPARE(item->repaints, 2); +} + QTEST_MAIN(tst_QGraphicsItem) #include "tst_qgraphicsitem.moc" -- cgit v0.12 From 9ed567ca68d51552f89887aa5a300a5f6a6d8ac3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Nilsen?= Date: Mon, 8 Jun 2009 13:55:16 +0200 Subject: A partial QGraphicsItem update causes a full update to be discarded. E.g. item->update(QRectF(0, 0, 5, 5)); item->update(); The problem was that we discarded all update requests whenever the item was already marked as dirty. The dirty bit only means it has pending updates (which might be a full update). However, we have a separate bit for full updates (fullUpdatePending) so we have to check against that bit instead. Makes tst_QGraphicsProxyWidget::paintEvent happy. Another auto-test included. --- src/gui/graphicsview/qgraphicsitem.cpp | 4 ++-- tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp | 31 +++++++++++++++++++++++++- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index 80ad19d..2a062ab 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -3907,7 +3907,7 @@ bool QGraphicsItemPrivate::discardUpdateRequest(bool ignoreClipping, bool ignore // 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. return (!visible && !ignoreVisibleBit) - || (!ignoreDirtyBit && dirty) + || (!ignoreDirtyBit && fullUpdatePending) || !scene || (scene->d_func()->updateAll && scene->d_func()->hasSceneRect) || (!ignoreClipping && (childrenClippedToShape() && isClippedAway())) @@ -4163,7 +4163,7 @@ void QGraphicsItem::update(const QRectF &rect) } } // Only invalidate cache; item is already dirty. - if (d_ptr->dirty) + if (d_ptr->fullUpdatePending) return; } diff --git a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp index 5b297f6..41593b5 100644 --- a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp +++ b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp @@ -6428,10 +6428,25 @@ void tst_QGraphicsItem::deviceTransform() QCOMPARE(rect3->deviceTransform(deviceX).map(QPointF(50, 50)), mapResult3); } +class MyGraphicsView : public QGraphicsView +{ +public: + int repaints; + QRegion paintedRegion; + MyGraphicsView(QGraphicsScene *scene) : QGraphicsView(scene), repaints(0) {} + void paintEvent(QPaintEvent *e) + { + paintedRegion += e->region(); + ++repaints; + QGraphicsView::paintEvent(e); + } + void reset() { repaints = 0; paintedRegion = QRegion(); } +}; + void tst_QGraphicsItem::update() { QGraphicsScene scene; - QGraphicsView view(&scene); + MyGraphicsView view(&scene); view.show(); #ifdef Q_WS_X11 qt_x11_wait_for_window_manager(&view); @@ -6453,6 +6468,20 @@ void tst_QGraphicsItem::update() item->update(); qApp->processEvents(); QCOMPARE(item->repaints, 2); + + // Make sure a partial update doesn't cause a full update to be discarded. + view.reset(); + item->repaints = 0; + item->update(QRectF(0, 0, 5, 5)); + item->update(); + qApp->processEvents(); + QCOMPARE(item->repaints, 1); + QCOMPARE(view.repaints, 1); + const QRect itemDeviceBoundingRect = item->deviceTransform(view.viewportTransform()) + .mapRect(item->boundingRect()).toRect(); + const QRegion expectedRegion = itemDeviceBoundingRect.adjusted(-2, -2, 2, 2); + // The entire item's bounding rect (adjusted for antialiasing) should have been painted. + QCOMPARE(view.paintedRegion, expectedRegion); } QTEST_MAIN(tst_QGraphicsItem) -- cgit v0.12 From 56f23d4ccfc27f737d30e92ae5b3ecde6e8b0bbf Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Wed, 20 May 2009 16:38:47 +0200 Subject: Add (back) properties to QGraphicsItem to change the transformations component This reapply commit 8ad5020940f10d4ecc5c5e8b3b9656531cb84ef3 and its dependent change that has been reverted while rebasing the recursivepaint branch. With the new properties it is possible to easily animate transformations Reviewed-by: Andreas Documentation still need to be reviewed. --- src/gui/graphicsview/qgraphicsitem.cpp | 512 ++++++++++++++++++++----- src/gui/graphicsview/qgraphicsitem.h | 37 +- src/gui/graphicsview/qgraphicsitem_p.h | 56 ++- src/gui/graphicsview/qgraphicsscene.cpp | 10 +- src/gui/graphicsview/qgraphicsview.cpp | 2 +- src/gui/graphicsview/qgraphicswidget.h | 9 +- tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp | 199 ++++++++++ 7 files changed, 716 insertions(+), 109 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index 2a062ab..d962554 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -133,12 +133,8 @@ \section1 Transformation QGraphicsItem supports affine transformations in addition to its base - position, pos(). To change the item's transformation, you can either pass - a transformation matrix to setTransform(), or set the different transformation - properties (transformOrigin, x/y/zRotation, x/yScale, horizontal/verticalShear). - Note that setting the transformation matrix conflicts with using the properties. - Setting the properties will overwrite the transformation set with setTransform, - and using setTransform will reset the properties. + position, pos(). To change the item's transformation, you can pass + a transformation matrix to setTransform() Item transformations accumulate from parent to child, so if both a parent and child item are rotated 90 degrees, the child's total transformation will be 180 degrees. @@ -152,19 +148,18 @@ and scenePos(), which returns its position in scene coordinates. To reset an item's matrix, call resetTransform(). + Another way to apply transformation to an item is to use the , or set the + different transformation properties (transformOrigin, x/y/zRotation, x/yScale, + horizontal/verticalShear). Those properties come in addition to the base transformation + The order you set the transformation properties does not affect the resulting transformation The resulting transformation is always computed in the following order \code - [Origin] [RotateX] [RotateY] [RotateZ] [Shear] [Scale] [-Origin] + [Origin] [Base] [RotateX] [RotateY] [RotateZ] [Shear] [Scale] [-Origin] \endcode - So the transformation is equivalent to the following code - - \code - QTransform().translate(xOrigin, yOrigin).rotate(xRotation, Qt::XAxis).rotate(yRotation, Qt::YAxis).rotate(zRotation, Qt::ZAxis) - .shear(horizontalShear, verticalShear).scale(xScale, yScale).translate(-xOrigin, -yOrigin); - \endcode + Where [Base] is the stransformation set by setTransform \section1 Painting @@ -788,8 +783,8 @@ void QGraphicsItemPrivate::combineTransformToParent(QTransform *x, const QTransf if (itemIsUntransformable() && viewTransform) { *x = q_ptr->deviceTransform(*viewTransform); } else { - if (transform) - *x *= *transform; + if (transformData) + *x *= transformData->computedFullTransform(); if (!pos.isNull()) *x *= QTransform::fromTranslate(pos.x(), pos.y()); } @@ -811,8 +806,8 @@ void QGraphicsItemPrivate::combineTransformFromParent(QTransform *x, const QTran *x = q_ptr->deviceTransform(*viewTransform); } else { x->translate(pos.x(), pos.y()); - if (transform) - *x = *transform * *x; + if (transformData) + *x = transformData->computedFullTransform() * *x; } } @@ -975,16 +970,9 @@ void QGraphicsItemPrivate::childrenBoundingRectHelper(QTransform *x, QRectF *rec QGraphicsItem *child = children.at(i); QGraphicsItemPrivate *childd = child->d_ptr; bool hasPos = !childd->pos.isNull(); - if (hasPos || childd->transform) { + if (hasPos || childd->transformData) { // COMBINE - QTransform matrix; - if (childd->transform) - matrix = *childd->transform; - if (hasPos) { - const QPointF &p = childd->pos; - matrix *= QTransform::fromTranslate(p.x(), p.y()); - } - matrix *= *x; + QTransform matrix = childd->transformToParent() * *x; *rect |= matrix.mapRect(child->boundingRect()); if (!childd->children.isEmpty()) childd->childrenBoundingRectHelper(&matrix, rect); @@ -1136,8 +1124,7 @@ QGraphicsItem::~QGraphicsItem() if (d_ptr->scene) d_ptr->scene->d_func()->_q_removeItemLater(this); - if (d_ptr->transform) - delete d_ptr->transform; + delete d_ptr->transformData; delete d_ptr; @@ -2747,12 +2734,364 @@ QMatrix QGraphicsItem::matrix() const */ QTransform QGraphicsItem::transform() const { - if (!d_ptr->transform) + if (!d_ptr->transformData) return QTransform(); - return *d_ptr->transform; + return d_ptr->transformData->transform; +} + +/*! + \since 4.6 + + Returns the rotation around the X axis. + + The default is 0 + + \warning The value doesn't take in account any rotation set with the setTransform() method. + + \sa setXRotation(), {Transformations} +*/ +qreal QGraphicsItem::xRotation() const +{ + if (!d_ptr->transformData) + return 0; + return d_ptr->transformData->xRotation; } /*! + \since 4.6 + + Sets the rotation around the X axis to \a angle degrees. + + \warning The value doesn't take in account any rotation set with the setTransform() method. + + \sa xRotation(), setTransformOrigin(), {Transformations} +*/ +void QGraphicsItem::setXRotation(qreal angle) +{ + prepareGeometryChange(); + if (!d_ptr->transformData) + d_ptr->transformData = new QGraphicsItemPrivate::TransformData; + d_ptr->transformData->xRotation = angle; + d_ptr->dirtySceneTransform = 1; +} + +/*! + \since 4.6 + + Returns the rotation around the Y axis. + + The default is 0 + + \warning The value doesn't take in account any rotation set with the setTransform() method. + + \sa setYRotation(), {Transformations} +*/ +qreal QGraphicsItem::yRotation() const +{ + if (!d_ptr->transformData) + return 0; + return d_ptr->transformData->yRotation; +} + +/*! + \since 4.6 + + Sets the rotation around the Y axis to \a angle degrees. + + \warning The value doesn't take in account any rotation set with the setTransform() method. + + \sa yRotation(), setTransformOrigin() {Transformations} +*/ +void QGraphicsItem::setYRotation(qreal angle) +{ + prepareGeometryChange(); + if (!d_ptr->transformData) + d_ptr->transformData = new QGraphicsItemPrivate::TransformData; + d_ptr->transformData->yRotation = angle; + d_ptr->dirtySceneTransform = 1; +} + +/*! + \since 4.6 + + Returns the rotation around the Z axis. + + The default is 0 + + \warning The value doesn't take in account any rotation set with the setTransform() method. + + \sa setZRotation(), {Transformations} +*/ +qreal QGraphicsItem::zRotation() const +{ + if (!d_ptr->transformData) + return 0; + return d_ptr->transformData->zRotation; +} + +/*! + \since 4.6 + + Sets the rotation around the Z axis to \a angle degrees. + + \warning The value doesn't take in account any rotation set with the setTransform() method. + + \sa zRotation(), setTransformOrigin(), {Transformations} +*/ +void QGraphicsItem::setZRotation(qreal angle) +{ + prepareGeometryChange(); + if (!d_ptr->transformData) + d_ptr->transformData = new QGraphicsItemPrivate::TransformData; + d_ptr->transformData->zRotation = angle; + d_ptr->dirtySceneTransform = 1; +} + +/*! + \since 4.6 + + This convenience function set the rotation angles around the 3 axes + to \a x, \a y and \a z. + + \sa setXRotation(), setYRotation(), setZRotation(), {Transformations} +*/ +void QGraphicsItem::setRotation(qreal x, qreal y, qreal z) +{ + prepareGeometryChange(); + if (!d_ptr->transformData) + d_ptr->transformData = new QGraphicsItemPrivate::TransformData; + d_ptr->transformData->xRotation = x; + d_ptr->transformData->yRotation = y; + d_ptr->transformData->zRotation = z; + d_ptr->dirtySceneTransform = 1; +} + +/*! + \since 4.6 + + Returns the scale factor on the X axis. + + The default is 1 + + \warning The value doesn't take in account any scaling set with the setTransform() method. + + \sa setXScale(), {Transformations} +*/ +qreal QGraphicsItem::xScale() const +{ + if (!d_ptr->transformData) + return 1; + return d_ptr->transformData->xScale; +} + +/*! + \since 4.6 + + Sets the scale factor on the X axis to \a factor. + + \warning The value doesn't take in account any scaling set with the setTransform() method. + + \sa xScale(), setTransformOrigin(), {Transformations} +*/ +void QGraphicsItem::setXScale(qreal factor) +{ + prepareGeometryChange(); + if (!d_ptr->transformData) + d_ptr->transformData = new QGraphicsItemPrivate::TransformData; + d_ptr->transformData->xScale = factor; + d_ptr->dirtySceneTransform = 1; +} + +/*! + \since 4.6 + + Returns the scale factor on the Y axis. + + The default is 1 + + \warning The value doesn't take in account any scaling set with the setTransform() method. + + \sa setYScale(), {Transformations} +*/ +qreal QGraphicsItem::yScale() const +{ + if (!d_ptr->transformData) + return 1; + return d_ptr->transformData->yScale; +} + +/*! + \since 4.6 + + Sets the scale factor on the Y axis to \a factor. + + \warning The value doesn't take in account any scaling set with the setTransform() method. + + \sa yScale(), setTransformOrigin(), {Transformations} +*/ +void QGraphicsItem::setYScale(qreal factor) +{ + prepareGeometryChange(); + if (!d_ptr->transformData) + d_ptr->transformData = new QGraphicsItemPrivate::TransformData; + d_ptr->transformData->yScale = factor; + d_ptr->dirtySceneTransform = 1; +} + +/*! + \since 4.6 + + This convenience function set the scaling factors on X and Y axis to \a sx and \a sy. + + \warning The value doesn't take in account any scaling set with the setTransform() method. + + \sa setXScale(), setYScale(), {Transformations} +*/ +void QGraphicsItem::setScale(qreal sx, qreal sy) +{ + prepareGeometryChange(); + if (!d_ptr->transformData) + d_ptr->transformData = new QGraphicsItemPrivate::TransformData; + d_ptr->transformData->xScale = sx; + d_ptr->transformData->yScale = sy; + d_ptr->dirtySceneTransform = 1; +} + +/*! + \since 4.6 + + Returns the horizontal shear. + + The default is 0 + + \warning The value doesn't take in account any shearing set with the setTransform() method. + + \sa setHorizontalShear(), {Transformations} +*/ +qreal QGraphicsItem::horizontalShear() const +{ + if (!d_ptr->transformData) + return 0; + return d_ptr->transformData->horizontalShear; +} + +/*! + \since 4.6 + + Sets the horizontal shear to \a shear. + + \warning The value doesn't take in account any shearing set with the setTransform() method. + + \sa horizontalShear(), {Transformations} +*/ +void QGraphicsItem::setHorizontalShear(qreal shear) +{ + prepareGeometryChange(); + if (!d_ptr->transformData) + d_ptr->transformData = new QGraphicsItemPrivate::TransformData; + d_ptr->transformData->horizontalShear = shear; + d_ptr->dirtySceneTransform = 1; +} + +/*! + \since 4.6 + + Returns the vertical shear. + + The default is 0 + + \warning The value doesn't take in account any shearing set with the setTransform() method. + + \sa setHorizontalShear(), {Transformations} +*/ +qreal QGraphicsItem::verticalShear() const +{ + if (!d_ptr->transformData) + return 0; + return d_ptr->transformData->verticalShear; +} + +/*! + \since 4.6 + + Sets the vertical shear to \a shear. + + \warning The value doesn't take in account any shearing set with the setTransform() method. + + \sa verticalShear(), {Transformations} +*/ +void QGraphicsItem::setVerticalShear(qreal shear) +{ + prepareGeometryChange(); + if (!d_ptr->transformData) + d_ptr->transformData = new QGraphicsItemPrivate::TransformData; + d_ptr->transformData->verticalShear = shear; + d_ptr->dirtySceneTransform = 1; +} + +/*! + \since 4.6 + + This convenience function sets the horizontal shear to \a sh and the vertical shear to \a sv. + + \warning The value doesn't take in account any shearing set with the setTransform() method. + + \sa setHorizontalShear(), setVerticalShear() +*/ +void QGraphicsItem::setShear(qreal sh, qreal sv) +{ + prepareGeometryChange(); + if (!d_ptr->transformData) + d_ptr->transformData = new QGraphicsItemPrivate::TransformData; + d_ptr->transformData->horizontalShear = sh; + d_ptr->transformData->verticalShear = sv; + d_ptr->dirtySceneTransform = 1; +} + +/*! + \since 4.6 + + Returns the origin point using for transformation in item coordinate. + + The default is QPointF(0,0). + + \sa setTransformOrigin(), {Transformations} +*/ +QPointF QGraphicsItem::transformOrigin() const +{ + if (!d_ptr->transformData) + return QPointF(0,0); + return QPointF(d_ptr->transformData->xOrigin, d_ptr->transformData->yOrigin); +} + +/*! + \since 4.6 + + Sets the origin for transformation in item coordinate + + \sa transformOrigin(), {Transformations} +*/ +void QGraphicsItem::setTransformOrigin(const QPointF &origin) +{ + prepareGeometryChange(); + if (!d_ptr->transformData) + d_ptr->transformData = new QGraphicsItemPrivate::TransformData; + d_ptr->transformData->xOrigin = origin.x(); + d_ptr->transformData->yOrigin = origin.y(); + d_ptr->dirtySceneTransform = 1; +} + +/*! + \fn inline void setTransformOrigin(qreal x, qreal y) + + \since 4.6 + \overload + + \sa setTransformOrigin(), {Transformations} +*/ + + +/*! \obsolete Use sceneTransform() instead. @@ -2778,9 +3117,9 @@ QMatrix QGraphicsItem::sceneMatrix() const \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsitem.cpp 4 Unlike transform(), which returns only an item's local transformation, this - function includes the item's (and any parents') position. + function includes the item's (and any parents') position, and all the transfomation properties. - \sa transform(), setTransform(), scenePos(), {The Graphics View Coordinate System} + \sa transform(), setTransform(), scenePos(), {The Graphics View Coordinate System}, {Transformations} */ QTransform QGraphicsItem::sceneTransform() const { @@ -2848,7 +3187,8 @@ QTransform QGraphicsItem::deviceTransform(const QTransform &viewportTransform) c // COMBINE QTransform matrix; matrix.translate(mappedPoint.x(), mappedPoint.y()); - matrix = untransformedAncestor->transform() * matrix; + if (untransformedAncestor->d_ptr->transformData) + matrix = untransformedAncestor->d_ptr->transformData->computedFullTransform() * matrix; // Then transform and translate all children. for (int i = 0; i < parents.size(); ++i) { @@ -2904,7 +3244,7 @@ QTransform QGraphicsItem::itemTransform(const QGraphicsItem *other, bool *ok) co // This is other's parent if (otherParent == this) { const QPointF &otherPos = other->d_ptr->pos; - if (other->d_ptr->transform) { + if (other->d_ptr->transformData) { QTransform otherToParent; other->d_ptr->combineTransformFromParent(&otherToParent); return otherToParent.inverted(ok); @@ -2919,7 +3259,7 @@ QTransform QGraphicsItem::itemTransform(const QGraphicsItem *other, bool *ok) co // COMBINE const QPointF &itemPos = d_ptr->pos; const QPointF &otherPos = other->d_ptr->pos; - if (!d_ptr->transform && !other->d_ptr->transform) { + if (!d_ptr->transformData && !other->d_ptr->transformData) { QPointF delta = itemPos - otherPos; if (ok) *ok = true; @@ -2987,11 +3327,11 @@ QTransform QGraphicsItem::itemTransform(const QGraphicsItem *other, bool *ok) co */ void QGraphicsItem::setMatrix(const QMatrix &matrix, bool combine) { - if (!d_ptr->transform) - d_ptr->transform = new QTransform; + if (!d_ptr->transformData) + d_ptr->transformData = new QGraphicsItemPrivate::TransformData; - QTransform newTransform(combine ? QTransform(matrix) * *d_ptr->transform : QTransform(matrix)); - if (*d_ptr->transform == newTransform) + QTransform newTransform(combine ? QTransform(matrix) * d_ptr->transformData->transform : QTransform(matrix)); + if (d_ptr->transformData->transform == newTransform) return; // Notify the item that the transformation matrix is changing. @@ -2999,13 +3339,13 @@ void QGraphicsItem::setMatrix(const QMatrix &matrix, bool combine) if (notify) { newTransform = QTransform(qVariantValue(itemChange(ItemMatrixChange, qVariantFromValue(newTransform.toAffine())))); - if (*d_ptr->transform == newTransform) + if (d_ptr->transformData->transform == newTransform) return; } // Update and set the new transformation. prepareGeometryChange(); - *d_ptr->transform = newTransform; + d_ptr->transformData->transform = newTransform; d_ptr->dirtySceneTransform = 1; // Send post-notification. @@ -3028,31 +3368,30 @@ void QGraphicsItem::setMatrix(const QMatrix &matrix, bool combine) to map an item coordiate to a scene coordinate, or mapFromScene() to map from scene coordinates to item coordinates. - \warning using this function conflicts with using the transformation properties. - If you set a transformation, getting the properties will return default values. + \warning using this function doesnt affect the value of the transformation properties - \sa transform(), setRotation(), setScale(), setShear(), setTransformOrigin() {The Graphics View Coordinate System} + \sa transform(), setRotation(), setScale(), setShear(), setTransformOrigin(), {The Graphics View Coordinate System}, {Transformations} */ void QGraphicsItem::setTransform(const QTransform &matrix, bool combine) { - if (!d_ptr->transform) - d_ptr->transform = new QTransform; + if (!d_ptr->transformData) + d_ptr->transformData = new QGraphicsItemPrivate::TransformData; - QTransform newTransform(combine ? matrix * *d_ptr->transform : matrix); - if (*d_ptr->transform == newTransform) + QTransform newTransform(combine ? matrix * d_ptr->transformData->transform : matrix); + if (d_ptr->transformData->transform == newTransform) return; // Notify the item that the transformation matrix is changing. bool notify = itemChangeEnabled(ItemTransformChange); if (notify) { newTransform = qVariantValue(itemChange(ItemTransformChange, qVariantFromValue(newTransform))); - if (*d_ptr->transform == newTransform) + if (d_ptr->transformData->transform == newTransform) return; } // Update and set the new transformation. prepareGeometryChange(); - *d_ptr->transform = newTransform; + d_ptr->transformData->transform = newTransform; d_ptr->dirtySceneTransform = 1; // Send post-notification. @@ -3096,8 +3435,7 @@ void QGraphicsItem::resetTransform() \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsitem.cpp 6 - \warning using this function conflicts with using the transformation properties. - Getting those properties after using this function will return default values. + \warning using this functionhas no effect on the zRotation value \sa setTransform(), transform(), scale(), shear(), translate() */ @@ -3118,8 +3456,7 @@ void QGraphicsItem::rotate(qreal angle) \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsitem.cpp 7 - \warning using this function conflicts with using the transformation properties. - Getting those properties after using this function will return default values. + \warning using this function has no effect on the xScale or yScale value \sa setTransform(), transform() */ @@ -3134,8 +3471,7 @@ void QGraphicsItem::scale(qreal sx, qreal sy) Shears the current item transformation by (\a sh, \a sv). - \warning using this function conflicts with using the transformation properties. - Getting those properties after using this function will return default values. + \warning using this function has no effect on the horizontalShear or verticalShear value \sa setTransform(), transform() */ @@ -3154,9 +3490,6 @@ void QGraphicsItem::shear(qreal sh, qreal sv) setPos() instead; this function changes the item's translation, which is conceptually separate from its position. - \warning using this function conflicts with using the transformation properties. - Getting those properties after using this function will return default values. - \sa setTransform(), transform() */ void QGraphicsItem::translate(qreal dx, qreal dy) @@ -3330,7 +3663,7 @@ QRectF QGraphicsItem::sceneBoundingRect() const const QGraphicsItemPrivate *itemd; do { itemd = parentItem->d_ptr; - if (itemd->transform) + if (itemd->transformData) break; offset += itemd->pos; } while ((parentItem = itemd->parent)); @@ -4030,18 +4363,10 @@ void QGraphicsItemPrivate::updateCachedClipPathFromSetPosHelper(const QPointF &n // Find closest clip ancestor and transform. Q_Q(QGraphicsItem); // COMBINE - QTransform thisToParentTransform = transform - ? *transform * QTransform::fromTranslate(newPos.x(), newPos.y()) - : QTransform::fromTranslate(newPos.x(), newPos.y()); + QTransform thisToParentTransform = transformToParent(); QGraphicsItem *clipParent = parent; while (clipParent && !(clipParent->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape)) { - // COMBINE - if (clipParent->d_ptr->transform) - thisToParentTransform *= *clipParent->d_ptr->transform; - if (!clipParent->d_ptr->pos.isNull()) { - thisToParentTransform *= QTransform::fromTranslate(clipParent->d_ptr->pos.x(), - clipParent->d_ptr->pos.y()); - } + thisToParentTransform *= clipParent->d_ptr->transformToParent(); clipParent = clipParent->d_ptr->parent; } @@ -4428,9 +4753,9 @@ QPointF QGraphicsItem::mapToItem(const QGraphicsItem *item, const QPointF &point QPointF QGraphicsItem::mapToParent(const QPointF &point) const { // COMBINE - if (!d_ptr->transform) + if (!d_ptr->transformData) return point + d_ptr->pos; - return d_ptr->transform->map(point) + d_ptr->pos; + return d_ptr->transformToParent().map(point); } /*! @@ -4496,9 +4821,9 @@ QPolygonF QGraphicsItem::mapToItem(const QGraphicsItem *item, const QRectF &rect QPolygonF QGraphicsItem::mapToParent(const QRectF &rect) const { // COMBINE - if (!d_ptr->transform) + if (!d_ptr->transformData) return rect.translated(d_ptr->pos); - return d_ptr->transform->map(rect).translated(d_ptr->pos); + return d_ptr->transformToParent().map(rect); } /*! @@ -4566,8 +4891,9 @@ QRectF QGraphicsItem::mapRectToItem(const QGraphicsItem *item, const QRectF &rec QRectF QGraphicsItem::mapRectToParent(const QRectF &rect) const { // COMBINE - QRectF r = !d_ptr->transform ? rect : d_ptr->transform->mapRect(rect); - return r.translated(d_ptr->pos); + if (!d_ptr->transformData) + return rect.translated(d_ptr->pos); + return d_ptr->transformToParent().mapRect(rect); } /*! @@ -4639,8 +4965,9 @@ QRectF QGraphicsItem::mapRectFromItem(const QGraphicsItem *item, const QRectF &r QRectF QGraphicsItem::mapRectFromParent(const QRectF &rect) const { // COMBINE - QRectF r = rect.translated(-d_ptr->pos); - return d_ptr->transform ? d_ptr->transform->inverted().mapRect(r) : r; + if (!d_ptr->transformData) + return rect.translated(-d_ptr->pos); + return d_ptr->transformToParent().inverted().mapRect(rect); } /*! @@ -4700,9 +5027,9 @@ QPolygonF QGraphicsItem::mapToItem(const QGraphicsItem *item, const QPolygonF &p QPolygonF QGraphicsItem::mapToParent(const QPolygonF &polygon) const { // COMBINE - if (!d_ptr->transform) + if (!d_ptr->transformData) return polygon.translated(d_ptr->pos); - return d_ptr->transform->map(polygon).translated(d_ptr->pos); + return d_ptr->transformToParent().map(polygon); } /*! @@ -4745,9 +5072,9 @@ QPainterPath QGraphicsItem::mapToItem(const QGraphicsItem *item, const QPainterP QPainterPath QGraphicsItem::mapToParent(const QPainterPath &path) const { // COMBINE - if (!d_ptr->transform) + if (!d_ptr->transformData) return path.translated(d_ptr->pos); - return d_ptr->transform->map(path).translated(d_ptr->pos); + return d_ptr->transformToParent().map(path); } /*! @@ -4797,8 +5124,8 @@ QPointF QGraphicsItem::mapFromItem(const QGraphicsItem *item, const QPointF &poi QPointF QGraphicsItem::mapFromParent(const QPointF &point) const { // COMBINE - if (d_ptr->transform) - return d_ptr->transform->inverted().map(point - d_ptr->pos); + if (d_ptr->transformData) + return d_ptr->transformToParent().inverted().map(point); return point - d_ptr->pos; } @@ -4866,8 +5193,9 @@ QPolygonF QGraphicsItem::mapFromItem(const QGraphicsItem *item, const QRectF &re QPolygonF QGraphicsItem::mapFromParent(const QRectF &rect) const { // COMBINE - QRectF r = rect.translated(-d_ptr->pos); - return d_ptr->transform ? d_ptr->transform->inverted().map(r) : r; + if (!d_ptr->transformData) + return rect.translated(-d_ptr->pos); + return d_ptr->transformToParent().inverted().map(rect); } /*! @@ -4923,9 +5251,9 @@ QPolygonF QGraphicsItem::mapFromItem(const QGraphicsItem *item, const QPolygonF QPolygonF QGraphicsItem::mapFromParent(const QPolygonF &polygon) const { // COMBINE - QPolygonF p = polygon; - p.translate(-d_ptr->pos); - return d_ptr->transform ? d_ptr->transform->inverted().map(p) : p; + if (!d_ptr->transformData) + return polygon.translated(-d_ptr->pos); + return d_ptr->transformToParent().inverted().map(polygon); } /*! @@ -4966,9 +5294,9 @@ QPainterPath QGraphicsItem::mapFromItem(const QGraphicsItem *item, const QPainte QPainterPath QGraphicsItem::mapFromParent(const QPainterPath &path) const { // COMBINE - QPainterPath p(path); - p.translate(-d_ptr->pos); - return d_ptr->transform ? d_ptr->transform->inverted().map(p) : p; + if (!d_ptr->transformData) + return path.translated(-d_ptr->pos); + return d_ptr->transformToParent().inverted().map(path); } /*! diff --git a/src/gui/graphicsview/qgraphicsitem.h b/src/gui/graphicsview/qgraphicsitem.h index 7c87176..67b57e0 100644 --- a/src/gui/graphicsview/qgraphicsitem.h +++ b/src/gui/graphicsview/qgraphicsitem.h @@ -248,10 +248,39 @@ public: void setTransform(const QTransform &matrix, bool combine = false); void resetTransform(); - void rotate(qreal angle); - void scale(qreal sx, qreal sy); - void shear(qreal sh, qreal sv); - void translate(qreal dx, qreal dy); + void rotate(qreal angle); // ### obsolete + void scale(qreal sx, qreal sy); // ### obsolete + void shear(qreal sh, qreal sv); // ### obsolete + void translate(qreal dx, qreal dy); // ### obsolete + + qreal xRotation() const; + void setXRotation(qreal angle); + + qreal yRotation() const; + void setYRotation(qreal angle); + + qreal zRotation() const; + void setZRotation(qreal angle); + void setRotation(qreal x, qreal y, qreal z); + + qreal xScale() const; + void setXScale(qreal factor); + + qreal yScale() const; + void setYScale(qreal factor); + void setScale(qreal sx, qreal sy); + + qreal horizontalShear() const; + void setHorizontalShear(qreal shear); + + qreal verticalShear() const; + void setVerticalShear(qreal shear); + void setShear(qreal sh, qreal sv); + + QPointF transformOrigin() const; + void setTransformOrigin(const QPointF &origin); + inline void setTransformOrigin(qreal x, qreal y) + { setTransformOrigin(QPointF(x,y)); } virtual void advance(int phase); diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index d884b16..62ef36a 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -115,7 +115,7 @@ public: opacity(1.), scene(0), parent(0), - transform(0), + transformData(0), index(-1), depth(0), acceptedMouseButtons(0x1f), @@ -147,8 +147,8 @@ public: dirtyChildrenBoundingRect(1), paintedViewBoundingRectsNeedRepaint(0), dirtySceneTransform(1), - itemChangesEnabled(0xffff), geometryChanged(0), + itemChangesEnabled(0xffff), globalStackingOrder(-1), q_ptr(0) { @@ -352,6 +352,8 @@ public: || (childrenCombineOpacity() && isFullyTransparent()); } + inline QTransform transformToParent() const; + QPainterPath cachedClipPath; QRectF childrenBoundingRect; QRectF needsRepaint; @@ -362,7 +364,8 @@ public: QGraphicsScene *scene; QGraphicsItem *parent; QList children; - QTransform *transform; + class TransformData; + TransformData *transformData; QTransform sceneTransform; int index; int depth; @@ -399,16 +402,57 @@ public: quint32 dirtyChildrenBoundingRect : 1; quint32 paintedViewBoundingRectsNeedRepaint : 1; quint32 dirtySceneTransform : 1; - quint32 itemChangesEnabled : 16; quint32 geometryChanged : 1; - quint32 padding : 2; // feel free to use + quint32 unused : 2; // feel free to use + quint32 itemChangesEnabled : 16; // Optional stacking order int globalStackingOrder; - QGraphicsItem *q_ptr; }; +struct QGraphicsItemPrivate::TransformData { + QTransform transform; + qreal xScale; + qreal yScale; + qreal xRotation; + qreal yRotation; + qreal zRotation; + qreal horizontalShear; + qreal verticalShear; + qreal xOrigin; + qreal yOrigin; + + TransformData() : + xScale(1.0), yScale(1.0), xRotation(0.0), yRotation(0.0), zRotation(0.0), + horizontalShear(0.0), verticalShear(0.0), xOrigin(0.0), yOrigin(0.0) + {} + + QTransform computedFullTransform() const + { + QTransform x; + x.translate(xOrigin, yOrigin); + x = transform * x; + x.rotate(xRotation, Qt::XAxis); + x.rotate(yRotation, Qt::YAxis); + x.rotate(zRotation, Qt::ZAxis); + x.shear(horizontalShear, verticalShear); + x.scale(xScale, yScale); + x.translate(-xOrigin, -yOrigin); + return x; + } +}; + +/* + return the full transform of the item to the parent. This include the position and all the transform data +*/ +inline QTransform QGraphicsItemPrivate::transformToParent() const +{ + QTransform matrix; + combineTransformToParent(&matrix); + return matrix; +} + QT_END_NAMESPACE #endif // QT_NO_GRAPHICSVIEW diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index ad392b0..1014550 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -1737,7 +1737,7 @@ void QGraphicsScenePrivate::childItems_helper(QList *items, QList &children = parent->d_ptr->children; for (int i = 0; i < children.size(); ++i) { QGraphicsItem *item = children.at(i); - if (item->d_ptr->transform && !item->d_ptr->transform->isInvertible()) + if (item->d_ptr->transformData && !item->d_ptr->transformData->computedFullTransform().isInvertible()) continue; // Skip invisible items and all their children. @@ -1777,7 +1777,7 @@ void QGraphicsScenePrivate::childItems_helper(QList *items, QList &children = parent->d_ptr->children; for (int i = 0; i < children.size(); ++i) { QGraphicsItem *item = children.at(i); - if (item->d_ptr->transform && !item->d_ptr->transform->isInvertible()) + if (item->d_ptr->transformData && !item->d_ptr->transformData->computedFullTransform().isInvertible()) continue; // Skip invisible items and all their children. @@ -1813,7 +1813,7 @@ void QGraphicsScenePrivate::childItems_helper(QList *items, if ((keep || !(item->flags() & QGraphicsItem::ItemClipsChildrenToShape)) && !item->d_ptr->children.isEmpty()) { // Recurse into children. - if (!item->d_ptr->transform || item->d_ptr->transform->type() <= QTransform::TxScale) { + if (!item->d_ptr->transformData || item->d_ptr->transformData->computedFullTransform().type() <= QTransform::TxScale) { // Rect childItems_helper(items, item, item->mapRectFromParent(rect), mode); } else { @@ -1843,7 +1843,7 @@ void QGraphicsScenePrivate::childItems_helper(QList *items, QList &children = parent->d_ptr->children; for (int i = 0; i < children.size(); ++i) { QGraphicsItem *item = children.at(i); - if (item->d_ptr->transform && !item->d_ptr->transform->isInvertible()) + if (item->d_ptr->transformData && !item->d_ptr->transformData->computedFullTransform().isInvertible()) continue; // Skip invisible items. @@ -1902,7 +1902,7 @@ void QGraphicsScenePrivate::childItems_helper(QList *items, QList &children = parent->d_ptr->children; for (int i = 0; i < children.size(); ++i) { QGraphicsItem *item = children.at(i); - if (item->d_ptr->transform && !item->d_ptr->transform->isInvertible()) + if (item->d_ptr->transformData && !item->d_ptr->transformData->computedFullTransform().isInvertible()) continue; // Skip invisible items. diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp index a9fc563..166bcb9 100644 --- a/src/gui/graphicsview/qgraphicsview.cpp +++ b/src/gui/graphicsview/qgraphicsview.cpp @@ -752,7 +752,7 @@ QRect QGraphicsViewPrivate::mapToViewRect(const QGraphicsItem *item, const QRect const QGraphicsItemPrivate *itemd; do { itemd = parentItem->d_ptr; - if (itemd->transform) + if (itemd->transformData) break; offset += itemd->pos; } while ((parentItem = itemd->parent)); diff --git a/src/gui/graphicsview/qgraphicswidget.h b/src/gui/graphicsview/qgraphicswidget.h index 34f1c5f..a5c9068 100644 --- a/src/gui/graphicsview/qgraphicswidget.h +++ b/src/gui/graphicsview/qgraphicswidget.h @@ -81,7 +81,14 @@ class Q_GUI_EXPORT QGraphicsWidget : public QObject, public QGraphicsItem, publi Q_PROPERTY(qreal opacity READ opacity WRITE setOpacity) Q_PROPERTY(QPointF pos READ pos WRITE setPos) Q_PROPERTY(QRectF geometry READ geometry WRITE setGeometry) - + Q_PROPERTY(QPointF transformOrigin READ transformOrigin WRITE setTransformOrigin) + Q_PROPERTY(qreal xRotation READ xRotation WRITE setXRotation) + Q_PROPERTY(qreal yRotation READ yRotation WRITE setYRotation) + Q_PROPERTY(qreal zRotation READ zRotation WRITE setZRotation) + Q_PROPERTY(qreal xScale READ xScale WRITE setXScale) + Q_PROPERTY(qreal yScale READ yScale WRITE setYScale) + Q_PROPERTY(qreal horizontalShear READ horizontalShear WRITE setHorizontalShear) + Q_PROPERTY(qreal verticalShear READ verticalShear WRITE setVerticalShear) public: QGraphicsWidget(QGraphicsItem *parent = 0, Qt::WindowFlags wFlags = 0); ~QGraphicsWidget(); diff --git a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp index 41593b5..82c173b 100644 --- a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp +++ b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp @@ -220,6 +220,8 @@ private slots: void deviceTransform_data(); void deviceTransform(); void update(); + void setTransformProperties_data(); + void setTransformProperties(); // task specific tests below me void task141694_textItemEnsureVisible(); @@ -6484,5 +6486,202 @@ void tst_QGraphicsItem::update() QCOMPARE(view.paintedRegion, expectedRegion); } +void tst_QGraphicsItem::setTransformProperties_data() +{ + QTest::addColumn("origin"); + QTest::addColumn("rotationX"); + QTest::addColumn("rotationY"); + QTest::addColumn("rotationZ"); + QTest::addColumn("scaleX"); + QTest::addColumn("scaleY"); + QTest::addColumn("shearX"); + QTest::addColumn("shearY"); + + QTest::newRow("nothing") << QPointF() << qreal(0.0) << qreal(0.0) << qreal(0.0) + << qreal(1.0) << qreal(1.0) << qreal(0.0) << qreal(0.0); + + QTest::newRow("rotationZ") << QPointF() << qreal(0.0) << qreal(0.0) << qreal(42.2) + << qreal(1.0) << qreal(1.0) << qreal(0.0) << qreal(0.0); + + QTest::newRow("rotationXY") << QPointF() << qreal(12.5) << qreal(53.6) << qreal(0.0) + << qreal(1.0) << qreal(1.0) << qreal(0.0) << qreal(0.0); + + QTest::newRow("rotationXYZ") << QPointF() << qreal(-25) << qreal(12) << qreal(556) + << qreal(1.0) << qreal(1.0) << qreal(0.0) << qreal(0.0); + + QTest::newRow("rotationXYZ dicentred") << QPointF(-53, 25.2) + << qreal(-2578.2) << qreal(4565.2) << qreal(56) + << qreal(1.0) << qreal(1.0) << qreal(0.0) << qreal(0.0); + + QTest::newRow("Scale") << QPointF() << qreal(0.0) << qreal(0.0) << qreal(0.0) + << qreal(6) << qreal(0.5) << qreal(0.0) << qreal(0.0); + + QTest::newRow("Shear") << QPointF() << qreal(0.0) << qreal(0.0) << qreal(0.0) + << qreal(1.0) << qreal(1.0) << qreal(2.2) << qreal(0.5); + + QTest::newRow("Scale and Shear") << QPointF() << qreal(0.0) << qreal(0.0) << qreal(0.0) + << qreal(5.2) << qreal(2.1) << qreal(5.2) << qreal(5.5); + + QTest::newRow("Everything") << QPointF() << qreal(41) << qreal(-23) << qreal(0.56) + << qreal(8.2) << qreal(-0.2) << qreal(-12) << qreal(-0.8); + + QTest::newRow("Everything dicentred") << QPointF(qreal(22.3), qreal(-56.2)) << qreal(-175) << qreal(196) << qreal(-1260) + << qreal(4) << qreal(2) << qreal(2.56) << qreal(0.8); +} + +/** + * the normal QCOMPARE doesn't work because it doesn't use qFuzzyCompare + */ +#define QCOMPARE_TRANSFORM(X1, X2) QVERIFY(((X1)*(X2).inverted()).isIdentity()) + +void tst_QGraphicsItem::setTransformProperties() +{ + QFETCH(QPointF,origin); + QFETCH(qreal,rotationX); + QFETCH(qreal,rotationY); + QFETCH(qreal,rotationZ); + QFETCH(qreal,scaleX); + QFETCH(qreal,scaleY); + QFETCH(qreal,shearX); + QFETCH(qreal,shearY); + + QTransform result; + result.translate(origin.x(), origin.y()); + result.rotate(rotationX, Qt::XAxis); + result.rotate(rotationY, Qt::YAxis); + result.rotate(rotationZ, Qt::ZAxis); + result.shear(shearX, shearY); + result.scale(scaleX, scaleY); + result.translate(-origin.x(), -origin.y()); + + QGraphicsScene scene; + QGraphicsRectItem *item = new QGraphicsRectItem(QRectF(0, 0, 100, 100)); + scene.addItem(item); + + item->setRotation(rotationX, rotationY, rotationZ); + item->setScale(scaleX, scaleY); + item->setShear(shearX, shearY); + item->setTransformOrigin(origin); + + QCOMPARE(item->xRotation(), rotationX); + QCOMPARE(item->yRotation(), rotationY); + QCOMPARE(item->zRotation(), rotationZ); + QCOMPARE(item->xScale(), scaleX); + QCOMPARE(item->yScale(), scaleY); + QCOMPARE(item->horizontalShear(), shearX); + QCOMPARE(item->verticalShear(), shearY); + QCOMPARE(item->transformOrigin(), origin); + + QCOMPARE(QTransform(), item->transform()); + QCOMPARE(result, item->sceneTransform()); + + //----------------------------------------------------------------- + //Change the rotation Z + item->setZRotation(45); + QTransform result2; + result2.translate(origin.x(), origin.y()); + result2.rotate(rotationX, Qt::XAxis); + result2.rotate(rotationY, Qt::YAxis); + result2.rotate(45, Qt::ZAxis); + result2.shear(shearX, shearY); + result2.scale(scaleX, scaleY); + result2.translate(-origin.x(), -origin.y()); + + QCOMPARE(item->xRotation(), rotationX); + QCOMPARE(item->yRotation(), rotationY); + QCOMPARE(item->zRotation(), 45.0); + QCOMPARE(item->xScale(), scaleX); + QCOMPARE(item->yScale(), scaleY); + QCOMPARE(item->horizontalShear(), shearX); + QCOMPARE(item->verticalShear(), shearY); + QCOMPARE(item->transformOrigin(), origin); + + QCOMPARE(QTransform(), item->transform()); + QCOMPARE(result2, item->sceneTransform()); + + //----------------------------------------------------------------- + // calling setTransform() and setPos shoukld change the sceneTransform + item->setTransform(result); + item->setPos(100, -150.5); + + QCOMPARE(item->xRotation(), rotationX); + QCOMPARE(item->yRotation(), rotationY); + QCOMPARE(item->zRotation(), 45.0); + QCOMPARE(item->xScale(), scaleX); + QCOMPARE(item->yScale(), scaleY); + QCOMPARE(item->horizontalShear(), shearX); + QCOMPARE(item->verticalShear(), shearY); + QCOMPARE(item->transformOrigin(), origin); + QCOMPARE(result, item->transform()); + + QTransform result3; + + result3.translate(origin.x(), origin.y()); + result3 = result * result3; + result3.rotate(rotationX, Qt::XAxis); + result3.rotate(rotationY, Qt::YAxis); + result3.rotate(45, Qt::ZAxis); + result3.shear(shearX, shearY); + result3.scale(scaleX, scaleY); + result3.translate(-origin.x(), -origin.y()); + + result3 *= QTransform::fromTranslate(100, -150.5); //the pos; + + QCOMPARE(result3, item->sceneTransform()); + + //----------------------------------------------------- + // setting the propertiees should be the same as setting a transform + {//with center origin on the matrix + QGraphicsRectItem *item1 = new QGraphicsRectItem(QRectF(50.2, -150, 230.5, 119)); + scene.addItem(item1); + QGraphicsRectItem *item2 = new QGraphicsRectItem(QRectF(50.2, -150, 230.5, 119)); + scene.addItem(item2); + + item1->setPos(12.3, -5); + item2->setPos(12.3, -5); + item1->setRotation(rotationX, rotationY, rotationZ); + item1->setScale(scaleX, scaleY); + item1->setShear(shearX, shearY); + item1->setTransformOrigin(origin); + + item2->setTransform(result); + + QCOMPARE_TRANSFORM(item1->sceneTransform(), item2->sceneTransform()); + + QCOMPARE_TRANSFORM(item1->itemTransform(item2), QTransform()); + QCOMPARE_TRANSFORM(item2->itemTransform(item1), QTransform()); + } + + {//with center origin on the item + QGraphicsRectItem *item1 = new QGraphicsRectItem(QRectF(50.2, -150, 230.5, 119)); + scene.addItem(item1); + QGraphicsRectItem *item2 = new QGraphicsRectItem(QRectF(50.2, -150, 230.5, 119)); + scene.addItem(item2); + + item1->setPos(12.3, -5); + item2->setPos(12.3, -5); + item1->setTransformOrigin(origin); + item2->setTransformOrigin(origin); + + item1->setRotation(rotationX, rotationY, rotationZ); + item1->setScale(scaleX, scaleY); + item1->setShear(shearX, shearY); + + QTransform tr; + tr.rotate(rotationX, Qt::XAxis); + tr.rotate(rotationY, Qt::YAxis); + tr.rotate(rotationZ, Qt::ZAxis); + tr.shear(shearX, shearY); + tr.scale(scaleX, scaleY); + + item2->setTransform(tr); + + QCOMPARE_TRANSFORM(item1->sceneTransform(), item2->sceneTransform()); + + QCOMPARE_TRANSFORM(item1->itemTransform(item2), QTransform()); + QCOMPARE_TRANSFORM(item2->itemTransform(item1), QTransform()); + } +} + QTEST_MAIN(tst_QGraphicsItem) #include "tst_qgraphicsitem.moc" -- cgit v0.12 From 9ba5a561b017ec028d675627df2eda5b13e3a6fc Mon Sep 17 00:00:00 2001 From: Alexis Menard Date: Mon, 8 Jun 2009 14:49:44 +0200 Subject: Fix two regressions in Plasma. The painter state proctection was not properly pass to drawItemHelper. The second is a double conversion to deviceTransform in createStyleOption of QGraphicsItem. Since the recursive drawing already give a transform in device mode we don't need to convert it two times. Reviewed-by:andreas --- src/gui/graphicsview/qgraphicsitem.cpp | 6 +-- src/gui/graphicsview/qgraphicsscene.cpp | 2 +- tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp | 53 ++++++++++++++++++++++ tests/auto/qgraphicswidget/tst_qgraphicswidget.cpp | 36 +++++++++++++++ 4 files changed, 92 insertions(+), 5 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index d962554..7f22c80 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -1016,14 +1016,12 @@ void QGraphicsItemPrivate::initStyleOption(QStyleOptionGraphicsItem *option, con return; // Initialize QStyleOptionGraphicsItem specific values (matrix, exposedRect). - - const QTransform itemToViewportTransform = q->deviceTransform(worldTransform); - option->matrix = itemToViewportTransform.toAffine(); //### discards perspective + option->matrix = worldTransform.toAffine(); //### discards perspective if (!allItems) { // Determine the item's exposed area option->exposedRect = QRectF(); - const QTransform reverseMap = itemToViewportTransform.inverted(); + const QTransform reverseMap = worldTransform.inverted(); const QVector exposedRects(exposedRegion.rects()); for (int i = 0; i < exposedRects.size(); ++i) { option->exposedRect |= reverseMap.mapRect(exposedRects.at(i)); diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index 1014550..28d65da 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -5254,7 +5254,7 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * if (clipsToShape) painter->setClipPath(item->shape(), Qt::IntersectClip); painter->setOpacity(opacity); - drawItemHelper(item, painter, &styleOptionTmp, widget, false); + drawItemHelper(item, painter, &styleOptionTmp, widget, painterStateProtection); if (savePainter) painter->restore(); diff --git a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp index 82c173b..7a789c5 100644 --- a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp +++ b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp @@ -44,6 +44,7 @@ #include #include +#include #include #include #include @@ -222,6 +223,7 @@ private slots: void update(); void setTransformProperties_data(); void setTransformProperties(); + void itemUsesExtendedStyleOption(); // task specific tests below me void task141694_textItemEnsureVisible(); @@ -6449,6 +6451,7 @@ void tst_QGraphicsItem::update() { QGraphicsScene scene; MyGraphicsView view(&scene); + view.show(); #ifdef Q_WS_X11 qt_x11_wait_for_window_manager(&view); @@ -6683,5 +6686,55 @@ void tst_QGraphicsItem::setTransformProperties() } } +class MyStyleOptionTester : public QGraphicsRectItem +{ +public: + MyStyleOptionTester(const QRectF &rect) + : QGraphicsRectItem(rect), startTrack(false) + {} + + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0) + { + if (startTrack) { + //Doesn't use the extended style option so the exposed rect is the boundingRect + if (!(flags() & QGraphicsItem::ItemUsesExtendedStyleOption)) { + QCOMPARE(option->exposedRect, boundingRect()); + } else { + QVERIFY(option->exposedRect != QRect()); + QVERIFY(option->exposedRect != boundingRect()); + } + } + QGraphicsRectItem::paint(painter, option, widget); + } + bool startTrack; +}; + +void tst_QGraphicsItem::itemUsesExtendedStyleOption() +{ + QGraphicsScene scene(0, 0, 300, 300); + QGraphicsPixmapItem item; + item.setFlag(QGraphicsItem::ItemUsesExtendedStyleOption, true); + QCOMPARE(item.flags(), QGraphicsItem::GraphicsItemFlags(QGraphicsItem::ItemUsesExtendedStyleOption)); + item.setFlag(QGraphicsItem::ItemUsesExtendedStyleOption, false); + QCOMPARE(item.flags(), 0); + + //We now test the content of the style option + MyStyleOptionTester *rect = new MyStyleOptionTester(QRect(0, 0, 100, 100)); + scene.addItem(rect); + rect->setPos(200, 200); + QGraphicsView view(&scene); + QTest::qWait(500); + rect->startTrack = true; + rect->update(10, 10, 10, 10); + QTest::qWait(125); + rect->startTrack = false; + rect->setFlag(QGraphicsItem::ItemUsesExtendedStyleOption, true); + QVERIFY((rect->flags() & QGraphicsItem::ItemUsesExtendedStyleOption)); + QTest::qWait(125); + rect->startTrack = true; + rect->update(10, 10, 10, 10); + QTest::qWait(125); +} + QTEST_MAIN(tst_QGraphicsItem) #include "tst_qgraphicsitem.moc" diff --git a/tests/auto/qgraphicswidget/tst_qgraphicswidget.cpp b/tests/auto/qgraphicswidget/tst_qgraphicswidget.cpp index 56d42c3..00f3155 100644 --- a/tests/auto/qgraphicswidget/tst_qgraphicswidget.cpp +++ b/tests/auto/qgraphicswidget/tst_qgraphicswidget.cpp @@ -155,6 +155,7 @@ private slots: void windowFlags_data(); void windowFlags(); void shortcutsDeletion(); + void painterStateProtectionOnWindowFrame(); // Task fixes void task236127_bspTreeIndexFails(); @@ -2282,6 +2283,41 @@ void tst_QGraphicsWidget::shortcutsDeletion() delete widget; } +class MessUpPainterWidget : public QGraphicsWidget +{ +public: + MessUpPainterWidget(QGraphicsItem * parent = 0, Qt::WindowFlags wFlags = 0) + : QGraphicsWidget(parent, wFlags) + {} + + void paintWindowFrame(QPainter * painter, const QStyleOptionGraphicsItem *option, QWidget *widget) + { + QCOMPARE(painter->opacity(), 1.0); + painter->setOpacity(0.0); + QGraphicsWidget::paintWindowFrame(painter, option, widget); + } + void paint(QPainter * painter, const QStyleOptionGraphicsItem *option, QWidget *widget) + { + QCOMPARE(painter->opacity(), 1.0); + painter->drawRect(0, 0, 100, 100); + QGraphicsWidget::paint(painter, option, widget); + } + +}; + +void tst_QGraphicsWidget::painterStateProtectionOnWindowFrame() +{ + MessUpPainterWidget *widget = new MessUpPainterWidget(0, Qt::Window); + QGraphicsScene scene(0, 0, 300, 300); + QGraphicsView view(&scene); + scene.addItem(widget); + view.show(); +#ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(&view); +#endif + QTest::qWait(500); +} + class ProxyStyle : public QCommonStyle { public: -- cgit v0.12 From e8e1cdaea063dc3613b38315ca401ef55340fcbb Mon Sep 17 00:00:00 2001 From: Andreas Aardal Hanssen Date: Mon, 8 Jun 2009 17:14:10 +0200 Subject: Revert "Add QGraphicsItem::itemChangeEnabled()." This reverts commit 0fc58ca3220083b9e10f88aab2e39824c2764db3. Conflicts: src/gui/graphicsview/qgraphicsitem.cpp src/gui/graphicsview/qgraphicsitem_p.h --- src/gui/graphicsview/qgraphicsitem.cpp | 240 ++++++++++---------------------- src/gui/graphicsview/qgraphicsitem.h | 5 - src/gui/graphicsview/qgraphicsitem_p.h | 4 +- src/gui/graphicsview/qgraphicsscene.cpp | 30 ++-- 4 files changed, 81 insertions(+), 198 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index 7f22c80..6679bd5 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -39,6 +39,8 @@ ** ****************************************************************************/ +#define QGRAPHICSITEM_NO_ITEMCHANGE + /*! \class QGraphicsItem \brief The QGraphicsItem class is the base class for all graphical @@ -844,13 +846,11 @@ void QGraphicsItemPrivate::setParentItemHelper(QGraphicsItem *newParent, bool de if (newParent == parent) return; - bool notify = q->itemChangeEnabled(QGraphicsItem::ItemParentChange); - if (notify) { - newParent = qVariantValue(q->itemChange(QGraphicsItem::ItemParentChange, - qVariantFromValue(newParent))); - if (newParent == parent) - return; - } + const QVariant newParentVariant(q->itemChange(QGraphicsItem::ItemParentChange, + qVariantFromValue(newParent))); + newParent = qVariantValue(newParentVariant); + if (newParent == parent) + return; if (QGraphicsWidget *w = isWidget ? static_cast(q) : q->parentWidget()) { // Update the child focus chain; when reparenting a widget that has a @@ -950,8 +950,7 @@ void QGraphicsItemPrivate::setParentItemHelper(QGraphicsItem *newParent, bool de dirtySceneTransform = 1; // Deliver post-change notification - if (notify) - q->itemChange(QGraphicsItem::ItemParentHasChanged, qVariantFromValue(newParent)); + q->itemChange(QGraphicsItem::ItemParentHasChanged, newParentVariant); } /*! @@ -1379,14 +1378,9 @@ void QGraphicsItem::setFlags(GraphicsItemFlags flags) // Notify change and check for adjustment. if (quint32(d_ptr->flags) == quint32(flags)) return; - - // Notify - bool notify = itemChangeEnabled(ItemFlagsChange); - if (notify) { - flags = GraphicsItemFlags(itemChange(ItemFlagsChange, quint32(flags)).toUInt()); - if (quint32(d_ptr->flags) == quint32(flags)) - return; - } + flags = GraphicsItemFlags(itemChange(ItemFlagsChange, quint32(flags)).toUInt()); + if (quint32(d_ptr->flags) == quint32(flags)) + return; // Flags that alter the geometry of the item (or its children). const quint32 geomChangeFlagsMask = (ItemClipsChildrenToShape | ItemClipsToShape | ItemIgnoresTransformations); @@ -1442,78 +1436,7 @@ void QGraphicsItem::setFlags(GraphicsItemFlags flags) } // Notify change. - if (notify) - itemChange(ItemFlagsHaveChanged, quint32(flags)); -} - -static const int itemChangeBits[] = { - /* ItemPositionChange */ 1 << 1, - /* ItemMatrixChange */ 1 << 2, - /* ItemVisibleChange */ 1 << 3, - /* ItemEnabledChange */ 1 << 4, - /* ItemSelectedChange */ 1 << 5, - /* ItemParentChange */ 1 << 6, - /* ItemChildAddedChange */ 1 << 7, - /* ItemChildRemovedChange */ 1 << 8, - /* ItemTransformChange */ 1 << 9, - /* ItemPositionHasChanged */ 1 << 1, - /* ItemTransformHasChanged */ 1 << 9, - /* ItemSceneChange */ 1 << 10, - /* ItemVisibleHasChanged */ 1 << 3, - /* ItemEnabledHasChanged */ 1 << 4, - /* ItemSelectedHasChanged */ 1 << 5, - /* ItemParentHasChanged */ 1 << 6, - /* ItemSceneHasChanged */ 1 << 10, - /* ItemCursorChange */ 1 << 11, - /* ItemCursorHasChanged */ 1 << 11, - /* ItemToolTipChange */ 1 << 12, - /* ItemToolTipHasChanged */ 1 << 12, - /* ItemFlagsChange */ 1 << 13, - /* ItemFlagsHaveChanged */ 1 << 13, - /* ItemZValueChange */ 1 << 14, - /* ItemZValueHasChanged */ 1 << 14, - /* ItemOpacityChange */ 1 << 15, - /* ItemOpacityHasChanged */ 1 << 15 -}; - -/*! - Returns true if \a change is enabled (i.e., QGraphicsItem will call - itemChange() whenever the respective change occurs); otherwise returns - false. - - \sa setItemChangeEnabled(), setItemChangesEnabled(), itemChange() -*/ -bool QGraphicsItem::itemChangeEnabled(GraphicsItemChange change) const -{ - return d_ptr->itemChangesEnabled & itemChangeBits[change]; -} - -/*! - If \a enabled is true, notifications for \a change are enabled; otherwise - they are disabled. By default, QGraphicsItem sends notifications for all - changes by calling itemChange(). - - \sa itemChangeEnabled(), setItemChangesEnabled(), itemChange() -*/ -void QGraphicsItem::setItemChangeEnabled(GraphicsItemChange change, bool enabled) -{ - if (enabled) { - d_ptr->itemChangesEnabled |= itemChangeBits[change]; - } else { - d_ptr->itemChangesEnabled &= itemChangeBits[change]; - } -} - -/*! - If \a enabled is true, all item change notifications are enabled; - otherwise, they are disabled. You can toggle individual notifications by - calling setItemChangeEnabled(). - - \sa itemChangeEnabled(), itemChange() -*/ -void QGraphicsItem::setItemChangesEnabled(bool enabled) -{ - d_ptr->itemChangesEnabled = enabled ? 0xffff : 0; + itemChange(ItemFlagsHaveChanged, quint32(flags)); } /*! @@ -1602,13 +1525,9 @@ QString QGraphicsItem::toolTip() const */ void QGraphicsItem::setToolTip(const QString &toolTip) { - bool notify = itemChangeEnabled(ItemToolTipChange); - QVariant toolTipVariant = toolTip; - if (notify) - toolTipVariant = itemChange(ItemToolTipChange, toolTipVariant); - d_ptr->setExtra(QGraphicsItemPrivate::ExtraToolTip, toolTipVariant); - if (notify) - itemChange(ItemToolTipHasChanged, toolTipVariant); + const QVariant toolTipVariant(itemChange(ItemToolTipChange, toolTip)); + d_ptr->setExtra(QGraphicsItemPrivate::ExtraToolTip, toolTipVariant.toString()); + itemChange(ItemToolTipHasChanged, toolTipVariant); } #endif // QT_NO_TOOLTIP @@ -1650,11 +1569,8 @@ QCursor QGraphicsItem::cursor() const */ void QGraphicsItem::setCursor(const QCursor &cursor) { - bool notify = itemChangeEnabled(ItemCursorChange); - QVariant cursorVariant = qVariantFromValue(cursor); - if (notify) - cursorVariant = itemChange(ItemCursorChange, cursorVariant); - d_ptr->setExtra(QGraphicsItemPrivate::ExtraCursor, cursorVariant); + const QVariant cursorVariant(itemChange(ItemCursorChange, qVariantFromValue(cursor))); + d_ptr->setExtra(QGraphicsItemPrivate::ExtraCursor, qVariantValue(cursorVariant)); d_ptr->hasCursor = 1; if (d_ptr->scene) { d_ptr->scene->d_func()->allItemsUseDefaultCursor = false; @@ -1673,8 +1589,7 @@ void QGraphicsItem::setCursor(const QCursor &cursor) } } } - if (notify) - itemChange(ItemCursorHasChanged, cursorVariant); + itemChange(ItemCursorHasChanged, cursorVariant); } /*! @@ -1771,12 +1686,10 @@ void QGraphicsItemPrivate::setVisibleHelper(bool newVisible, bool explicitly, bo if (parent && newVisible && !parent->d_ptr->visible) return; - // Notify - bool notify = q->itemChangeEnabled(QGraphicsItem::ItemVisibleChange); - if (notify) - newVisible = q_ptr->itemChange(QGraphicsItem::ItemVisibleChange, quint32(newVisible)).toBool(); - // Modify the property. + const QVariant newVisibleVariant(q_ptr->itemChange(QGraphicsItem::ItemVisibleChange, + quint32(newVisible))); + newVisible = newVisibleVariant.toBool(); if (visible == quint32(newVisible)) return; visible = newVisible; @@ -1843,8 +1756,7 @@ void QGraphicsItemPrivate::setVisibleHelper(bool newVisible, bool explicitly, bo } // Deliver post-change notification. - if (notify) - q_ptr->itemChange(QGraphicsItem::ItemVisibleHasChanged, newVisible); + q_ptr->itemChange(QGraphicsItem::ItemVisibleHasChanged, newVisibleVariant); } /*! @@ -1950,10 +1862,9 @@ void QGraphicsItemPrivate::setEnabledHelper(bool newEnabled, bool explicitly, bo } // Modify the property. - bool notify = q_ptr->itemChangeEnabled(QGraphicsItem::ItemEnabledChange); - if (notify) - newEnabled = q_ptr->itemChange(QGraphicsItem::ItemEnabledChange, quint32(newEnabled)).toBool(); - enabled = newEnabled; + const QVariant newEnabledVariant(q_ptr->itemChange(QGraphicsItem::ItemEnabledChange, + quint32(newEnabled))); + enabled = newEnabledVariant.toBool(); // Schedule redraw. if (update && scene) @@ -1965,8 +1876,7 @@ void QGraphicsItemPrivate::setEnabledHelper(bool newEnabled, bool explicitly, bo } // Deliver post-change notification. - if (notify) - q_ptr->itemChange(QGraphicsItem::ItemEnabledHasChanged, newEnabled); + q_ptr->itemChange(QGraphicsItem::ItemEnabledHasChanged, newEnabledVariant); } /*! @@ -2053,13 +1963,10 @@ void QGraphicsItem::setSelected(bool selected) selected = false; if (d_ptr->selected == selected) return; - bool notify = itemChangeEnabled(ItemSelectedChange); - bool newSelected = selected; - if (notify) { - newSelected = itemChange(ItemSelectedChange, quint32(selected)).toBool(); - if (d_ptr->selected == newSelected) - return; - } + const QVariant newSelectedVariant(itemChange(ItemSelectedChange, quint32(selected))); + bool newSelected = newSelectedVariant.toBool(); + if (d_ptr->selected == newSelected) + return; d_ptr->selected = newSelected; if (d_ptr->scene) { @@ -2076,8 +1983,7 @@ void QGraphicsItem::setSelected(bool selected) } // Deliver post-change notification. - if (notify) - itemChange(QGraphicsItem::ItemSelectedHasChanged, newSelected); + itemChange(QGraphicsItem::ItemSelectedHasChanged, newSelectedVariant); } /*! @@ -2143,12 +2049,13 @@ qreal QGraphicsItem::effectiveOpacity() const */ void QGraphicsItem::setOpacity(qreal opacity) { + // Notify change. +#ifndef QGRAPHICSITEM_NO_ITEMCHANGE + const QVariant newOpacityVariant(itemChange(ItemOpacityChange, double(opacity))); + qreal newOpacity = newOpacityVariant.toDouble(); +#else qreal newOpacity = opacity; - - // Notify - bool notify = itemChangeEnabled(ItemOpacityChange); - if (notify) - newOpacity = itemChange(ItemOpacityChange, double(newOpacity)).toDouble(); +#endif // Normalize. newOpacity = qBound(0.0, newOpacity, 1.0); @@ -2159,9 +2066,10 @@ void QGraphicsItem::setOpacity(qreal opacity) d_ptr->opacity = newOpacity; - // Notify - if (notify) - itemChange(ItemOpacityHasChanged, newOpacity); + // Notify change. +#ifndef QGRAPHICSITEM_NO_ITEMCHANGE + itemChange(ItemOpacityHasChanged, newOpacity); +#endif // Update. if (d_ptr->scene) @@ -2610,15 +2518,15 @@ void QGraphicsItemPrivate::setPosHelper(const QPointF &pos) if (this->pos == pos) return; + // Notify the item that the position is changing. +#ifndef QGRAPHICSITEM_NO_ITEMCHANGE + const QVariant newPosVariant(q->itemChange(QGraphicsItem::ItemPositionChange, pos)); + QPointF newPos = newPosVariant.toPointF(); + if (newPos == this->pos) + return; +#else QPointF newPos = pos; - - // Notify - bool notify = q->itemChangeEnabled(QGraphicsItem::ItemPositionChange); - if (notify) { - newPos = q->itemChange(QGraphicsItem::ItemPositionChange, pos).toPointF(); - if (newPos == this->pos) - return; - } +#endif // Update and repositition. inSetPosHelper = 1; @@ -2629,9 +2537,9 @@ void QGraphicsItemPrivate::setPosHelper(const QPointF &pos) dirtySceneTransform = 1; // Send post-notification. - if (notify) - q->itemChange(QGraphicsItem::ItemPositionHasChanged, newPos); - +#ifndef QGRAPHICSITEM_NO_ITEMCHANGE + q->itemChange(QGraphicsItem::ItemPositionHasChanged, newPosVariant); +#endif inSetPosHelper = 0; } @@ -3333,13 +3241,11 @@ void QGraphicsItem::setMatrix(const QMatrix &matrix, bool combine) return; // Notify the item that the transformation matrix is changing. - bool notify = itemChangeEnabled(ItemMatrixChange); - if (notify) { - newTransform = QTransform(qVariantValue(itemChange(ItemMatrixChange, - qVariantFromValue(newTransform.toAffine())))); - if (d_ptr->transformData->transform == newTransform) - return; - } + const QVariant newTransformVariant(itemChange(ItemTransformChange, + qVariantFromValue(newTransform))); + newTransform = qVariantValue(newTransformVariant); + if (d_ptr->transformData->transform == newTransform) + return; // Update and set the new transformation. prepareGeometryChange(); @@ -3347,8 +3253,7 @@ void QGraphicsItem::setMatrix(const QMatrix &matrix, bool combine) d_ptr->dirtySceneTransform = 1; // Send post-notification. - if (notify) - itemChange(ItemTransformHasChanged, qVariantFromValue(newTransform)); + itemChange(ItemTransformHasChanged, newTransformVariant); } /*! @@ -3380,12 +3285,12 @@ void QGraphicsItem::setTransform(const QTransform &matrix, bool combine) return; // Notify the item that the transformation matrix is changing. - bool notify = itemChangeEnabled(ItemTransformChange); - if (notify) { - newTransform = qVariantValue(itemChange(ItemTransformChange, qVariantFromValue(newTransform))); - if (d_ptr->transformData->transform == newTransform) - return; - } + // Notify the item that the transformation matrix is changing. + const QVariant newTransformVariant(itemChange(ItemTransformChange, + qVariantFromValue(newTransform))); + newTransform = qVariantValue(newTransformVariant); + if (d_ptr->transformData->transform == newTransform) + return; // Update and set the new transformation. prepareGeometryChange(); @@ -3393,8 +3298,7 @@ void QGraphicsItem::setTransform(const QTransform &matrix, bool combine) d_ptr->dirtySceneTransform = 1; // Send post-notification. - if (notify) - itemChange(ItemTransformHasChanged, qVariantFromValue(newTransform)); + itemChange(ItemTransformHasChanged, newTransformVariant); } /*! @@ -3561,13 +3465,10 @@ qreal QGraphicsItem::zValue() const */ void QGraphicsItem::setZValue(qreal z) { - bool notify = itemChangeEnabled(ItemZValueChange); - qreal newZ = z; - if (notify) { - newZ = itemChange(ItemZValueChange, double(z)).toDouble(); - if (newZ == d_ptr->z) - return; - } + const QVariant newZVariant(itemChange(ItemZValueChange, double(z))); + qreal newZ = qreal(newZVariant.toDouble()); + if (newZ == d_ptr->z) + return; d_ptr->z = newZ; if (d_ptr->parent) d_ptr->parent->d_ptr->needSortChildren = 1; @@ -3581,8 +3482,7 @@ void QGraphicsItem::setZValue(qreal z) d_ptr->scene->d_func()->invalidateSortCache(); } - if (notify) - itemChange(ItemZValueHasChanged, newZ); + itemChange(ItemZValueHasChanged, newZVariant); } /*! diff --git a/src/gui/graphicsview/qgraphicsitem.h b/src/gui/graphicsview/qgraphicsitem.h index 67b57e0..7e33c83 100644 --- a/src/gui/graphicsview/qgraphicsitem.h +++ b/src/gui/graphicsview/qgraphicsitem.h @@ -129,7 +129,6 @@ public: ItemZValueHasChanged, ItemOpacityChange, ItemOpacityHasChanged - // NB! Don't forget to increase d_ptr->itemChangesEnabled when adding a new entry. }; enum CacheMode { @@ -166,10 +165,6 @@ public: void setFlag(GraphicsItemFlag flag, bool enabled = true); void setFlags(GraphicsItemFlags flags); - bool itemChangeEnabled(GraphicsItemChange change) const; - void setItemChangeEnabled(GraphicsItemChange change, bool enabled); - void setItemChangesEnabled(bool enabled); - CacheMode cacheMode() const; void setCacheMode(CacheMode mode, const QSize &cacheSize = QSize()); diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index 62ef36a..13fee8f 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -148,7 +148,6 @@ public: paintedViewBoundingRectsNeedRepaint(0), dirtySceneTransform(1), geometryChanged(0), - itemChangesEnabled(0xffff), globalStackingOrder(-1), q_ptr(0) { @@ -403,8 +402,7 @@ public: quint32 paintedViewBoundingRectsNeedRepaint : 1; quint32 dirtySceneTransform : 1; quint32 geometryChanged : 1; - quint32 unused : 2; // feel free to use - quint32 itemChangesEnabled : 16; + quint32 unused : 17; // feel free to use // Optional stacking order int globalStackingOrder; diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index 28d65da..54fead1 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -662,10 +662,8 @@ void QGraphicsScenePrivate::_q_polishItems() const QVariant booleanTrueVariant(true); foreach (QGraphicsItem *item, unpolishedItems) { if (!item->d_ptr->explicitlyHidden) { - if (item->itemChangeEnabled(QGraphicsItem::ItemVisibleChange)) { - item->itemChange(QGraphicsItem::ItemVisibleChange, booleanTrueVariant); - item->itemChange(QGraphicsItem::ItemVisibleHasChanged, booleanTrueVariant); - } + item->itemChange(QGraphicsItem::ItemVisibleChange, booleanTrueVariant); + item->itemChange(QGraphicsItem::ItemVisibleHasChanged, booleanTrueVariant); } if (item->isWidget()) { QEvent event(QEvent::Polish); @@ -2969,12 +2967,9 @@ void QGraphicsScene::addItem(QGraphicsItem *item) // Notify the item that its scene is changing, and allow the item to // react. - QGraphicsScene *targetScene = this; - bool notify = item->itemChangeEnabled(QGraphicsItem::ItemSceneChange); - if (notify) { - targetScene = qVariantValue(item->itemChange(QGraphicsItem::ItemSceneChange, - qVariantFromValue(this))); - } + const QVariant newSceneVariant(item->itemChange(QGraphicsItem::ItemSceneChange, + qVariantFromValue(this))); + QGraphicsScene *targetScene = qVariantValue(newSceneVariant); if (targetScene != this) { if (targetScene && item->scene() != targetScene) targetScene->addItem(item); @@ -3085,8 +3080,7 @@ void QGraphicsScene::addItem(QGraphicsItem *item) emit selectionChanged(); // Deliver post-change notification - if (notify) - item->itemChange(QGraphicsItem::ItemSceneHasChanged, qVariantFromValue(targetScene)); + item->itemChange(QGraphicsItem::ItemSceneHasChanged, newSceneVariant); } /*! @@ -3350,12 +3344,9 @@ void QGraphicsScene::removeItem(QGraphicsItem *item) // Notify the item that it's scene is changing to 0, allowing the item to // react. - QGraphicsScene *targetScene = 0; - bool notify = item->itemChangeEnabled(QGraphicsItem::ItemSceneChange); - if (notify) { - targetScene = qVariantValue(item->itemChange(QGraphicsItem::ItemSceneChange, - qVariantFromValue(0))); - } + const QVariant newSceneVariant(item->itemChange(QGraphicsItem::ItemSceneChange, + qVariantFromValue(0))); + QGraphicsScene *targetScene = qVariantValue(newSceneVariant); if (targetScene != 0 && targetScene != this) { targetScene->addItem(item); return; @@ -3452,8 +3443,7 @@ void QGraphicsScene::removeItem(QGraphicsItem *item) emit selectionChanged(); // Deliver post-change notification - if (notify) - item->itemChange(QGraphicsItem::ItemSceneHasChanged, qVariantFromValue(targetScene)); + item->itemChange(QGraphicsItem::ItemSceneHasChanged, newSceneVariant); } /*! -- cgit v0.12 From c07239ac97dfce35a6b277c82ec5445e01eb2249 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Nilsen?= Date: Mon, 8 Jun 2009 14:15:22 +0200 Subject: Add another auto-test ensuring updates outside the brect are discared. --- tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp index 7a789c5..35a7bb9 100644 --- a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp +++ b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp @@ -6487,6 +6487,14 @@ void tst_QGraphicsItem::update() const QRegion expectedRegion = itemDeviceBoundingRect.adjusted(-2, -2, 2, 2); // The entire item's bounding rect (adjusted for antialiasing) should have been painted. QCOMPARE(view.paintedRegion, expectedRegion); + + // Make sure update requests outside the bounding rect are discarded. + view.reset(); + item->repaints = 0; + item->update(-15, -15, 5, 5); // Item's brect: (-10, -10, 20, 20) + qApp->processEvents(); + QCOMPARE(item->repaints, 0); + QCOMPARE(view.repaints, 0); } void tst_QGraphicsItem::setTransformProperties_data() -- cgit v0.12 From 8a5a52e95a8ec81ce4bc3bb0599cfab510c8400a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Nilsen?= Date: Mon, 8 Jun 2009 17:33:11 +0200 Subject: Auto-test to ensure moved items don't leave traces. See also: 1c9032f29d4500b33622d7510b6361c99d9af296 --- src/gui/graphicsview/qgraphicsscene.cpp | 3 +- tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp | 78 ++++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 1 deletion(-) diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index 54fead1..7038c3d 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -5156,8 +5156,9 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * QRectF brect = item->boundingRect(); // ### This does not take the clip into account. _q_adjustRect(&brect); - viewBoundingRect = transformTmp.mapRect(brect).toRect().adjusted(-1, -1, 1, 1); + viewBoundingRect = transformTmp.mapRect(brect).toRect(); item->d_ptr->paintedViewBoundingRects.insert(widget, viewBoundingRect); + viewBoundingRect.adjust(-1, -1, 1, 1); if (exposedRegion) viewBoundingRect &= exposedRegion->boundingRect(); } diff --git a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp index 35a7bb9..c6f9824 100644 --- a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp +++ b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp @@ -224,6 +224,7 @@ private slots: void setTransformProperties_data(); void setTransformProperties(); void itemUsesExtendedStyleOption(); + void moveItem(); // task specific tests below me void task141694_textItemEnsureVisible(); @@ -6744,5 +6745,82 @@ void tst_QGraphicsItem::itemUsesExtendedStyleOption() QTest::qWait(125); } +// Make sure we update moved items correctly. +void tst_QGraphicsItem::moveItem() +{ + QGraphicsScene scene; + scene.setSceneRect(-50, -50, 200, 200); + + MyGraphicsView view(&scene); + view.show(); +#ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(&view); +#endif + QTest::qWait(100); + + EventTester *parent = new EventTester; + EventTester *child = new EventTester(parent); + EventTester *grandChild = new EventTester(child); + +#define RESET_COUNTERS \ + parent->repaints = 0; \ + child->repaints = 0; \ + grandChild->repaints = 0; \ + view.reset(); + + scene.addItem(parent); + QTest::qWait(100); + + RESET_COUNTERS + + // Item's boundingRect: (-10, -10, 20, 20). + QRect parentDeviceBoundingRect = parent->deviceTransform(view.viewportTransform()) + .mapRect(parent->boundingRect()).toRect() + .adjusted(-2, -2, 2, 2); // Adjusted for antialiasing. + + parent->setPos(20, 20); + qApp->processEvents(); + QCOMPARE(parent->repaints, 1); + QCOMPARE(view.repaints, 1); + QRegion expectedParentRegion = parentDeviceBoundingRect; // old position + parentDeviceBoundingRect.translate(20, 20); + expectedParentRegion += parentDeviceBoundingRect; // new position + QCOMPARE(view.paintedRegion, expectedParentRegion); + + RESET_COUNTERS + + child->setPos(20, 20); + qApp->processEvents(); + QCOMPARE(parent->repaints, 1); + QCOMPARE(child->repaints, 1); + QCOMPARE(view.repaints, 1); + const QRegion expectedChildRegion = expectedParentRegion.translated(20, 20); + QCOMPARE(view.paintedRegion, expectedChildRegion); + + RESET_COUNTERS + + grandChild->setPos(20, 20); + qApp->processEvents(); + QCOMPARE(parent->repaints, 1); + QCOMPARE(child->repaints, 1); + QCOMPARE(grandChild->repaints, 1); + QCOMPARE(view.repaints, 1); + const QRegion expectedGrandChildRegion = expectedParentRegion.translated(40, 40); + QCOMPARE(view.paintedRegion, expectedGrandChildRegion); + + RESET_COUNTERS + + parent->translate(20, 20); + qApp->processEvents(); + QCOMPARE(parent->repaints, 1); + QCOMPARE(child->repaints, 1); + QCOMPARE(grandChild->repaints, 1); + QCOMPARE(view.repaints, 1); + expectedParentRegion.translate(20, 20); + expectedParentRegion += expectedChildRegion.translated(20, 20); + expectedParentRegion += expectedGrandChildRegion.translated(20, 20); + QCOMPARE(view.paintedRegion, expectedParentRegion); +} + QTEST_MAIN(tst_QGraphicsItem) #include "tst_qgraphicsitem.moc" -- cgit v0.12 From 50ddb3451007a94d87c064216603a3e3e6e8b9c6 Mon Sep 17 00:00:00 2001 From: Andreas Aardal Hanssen Date: Mon, 8 Jun 2009 18:58:57 +0200 Subject: Add ItemSendsGeometryChanges, replacing itemChangeEnabled(). This flag toggles whether we should send notifications for setPos, setMatrix, and setTransform. It's off by default. Docs have been updated. All autotests pass. This change also cleans up a bit so that we both have readable code, and keeping the optimized path for when we need to send the notifications. By enabling this flag by default we are going to trigger regressions in end-user code. Reviewed-by: bnilsen --- examples/graphicsview/elasticnodes/node.cpp | 1 + src/gui/graphicsview/qgraphicsitem.cpp | 161 ++++++++++++++----------- src/gui/graphicsview/qgraphicsitem.h | 3 +- src/gui/graphicsview/qgraphicsitem_p.h | 5 +- src/gui/graphicsview/qgraphicswidget.cpp | 3 + src/gui/graphicsview/qgraphicswidget_p.cpp | 2 + tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp | 58 ++++++++- 7 files changed, 158 insertions(+), 75 deletions(-) diff --git a/examples/graphicsview/elasticnodes/node.cpp b/examples/graphicsview/elasticnodes/node.cpp index 6942fa0..53fe994 100644 --- a/examples/graphicsview/elasticnodes/node.cpp +++ b/examples/graphicsview/elasticnodes/node.cpp @@ -52,6 +52,7 @@ Node::Node(GraphWidget *graphWidget) : graph(graphWidget) { setFlag(ItemIsMovable); + setFlag(ItemSendsGeometryChanges); setCacheMode(DeviceCoordinateCache); setZValue(1); } diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index 6679bd5..3138faa 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -39,8 +39,6 @@ ** ****************************************************************************/ -#define QGRAPHICSITEM_NO_ITEMCHANGE - /*! \class QGraphicsItem \brief The QGraphicsItem class is the base class for all graphical @@ -310,7 +308,14 @@ \value ItemHasNoContents The item does not paint anything (i.e., calling paint() on the item has no effect). You should set this flag on items that do not need to be painted to ensure that Graphics View avoids unnecessary - painting preparations. + painting preparations. This flag was introduced in Qt 4.6. + + \value ItemSendsGeometryChanges The item enables itemChange() + notifications for ItemPositionChange, ItemPositionHasChanged, + ItemMatrixChange, ItemTransformChange, and ItemTransformHasChanged. For + performance reasons, these notifications are disabled by default. You must + enable this flag to receive notifications for position and transform + changes. This flag was introduced in Qt 4.6. */ /*! @@ -349,33 +354,36 @@ changing. This value is obsolete; you can use ItemTransformChange instead. \value ItemPositionChange The item's position changes. This notification - is only sent when the item's local position changes, relative to its - parent, has changed (i.e., as a result of calling setPos() or - moveBy()). The value argument is the new position (i.e., a QPointF). You - can call pos() to get the original position. Do not call setPos() or - moveBy() in itemChange() as this notification is delivered; instead, you - can return the new, adjusted position from itemChange(). After this - notification, QGraphicsItem immediately sends the ItemPositionHasChanged - notification if the position changed. + is sent if the ItemSendsGeometryChanges flag is enabled, and when the + item's local position changes, relative to its parent (i.e., as a result + of calling setPos() or moveBy()). The value argument is the new position + (i.e., a QPointF). You can call pos() to get the original position. Do + not call setPos() or moveBy() in itemChange() as this notification is + delivered; instead, you can return the new, adjusted position from + itemChange(). After this notification, QGraphicsItem immediately sends the + ItemPositionHasChanged notification if the position changed. \value ItemPositionHasChanged The item's position has changed. This - notification is only sent after the item's local position, relative to its - parent, has changed. The value argument is the new position (the same as - pos()), and QGraphicsItem ignores the return value for this notification - (i.e., a read-only notification). + notification is sent if the ItemSendsGeometryChanges flag is enabled, and + after the item's local position, relative to its parent, has changed. The + value argument is the new position (the same as pos()), and QGraphicsItem + ignores the return value for this notification (i.e., a read-only + notification). \value ItemTransformChange The item's transformation matrix changes. This - notification is only sent when the item's local transformation matrix - changes (i.e., as a result of calling setTransform(). The value - argument is the new matrix (i.e., a QTransform); to get the old matrix, - call transform(). Do not call setTransform() or set any of the transformation - properties in itemChange() as this notification is delivered; - instead, you can return the new matrix from itemChange(). - This notification is not sent if you change the transformation properties. + notification is send if the ItemSendsGeometryChanges flag is enabled, and + when the item's local transformation matrix changes (i.e., as a result of + calling setTransform(). The value argument is the new matrix (i.e., a + QTransform); to get the old matrix, call transform(). Do not call + setTransform() or set any of the transformation properties in itemChange() + as this notification is delivered; instead, you can return the new matrix + from itemChange(). This notification is not sent if you change the + transformation properties. \value ItemTransformHasChanged The item's transformation matrix has - changed either because setTransform is called, or one of the transformation - properties is changed. This notification is only sent after the item's local + changed either because setTransform is called, or one of the + transformation properties is changed. This notification is sent if the + ItemSendsGeometryChanges flag is enabled, and after the item's local transformation matrix has changed. The value argument is the new matrix (same as transform()), and QGraphicsItem ignores the return value for this notification (i.e., a read-only notification). @@ -1369,7 +1377,9 @@ static void _q_qgraphicsItemSetFlag(QGraphicsItem *item, QGraphicsItem::Graphics item was selected, and \a flags does not enabled ItemIsSelectable, the item is automatically unselected. - By default, no flags are enabled. + By default, no flags are enabled. (QGraphicsWidget enables the + ItemSendsGeometryChanges flag by default in order to track position + changes.) \sa flags(), setFlag() */ @@ -2050,12 +2060,8 @@ qreal QGraphicsItem::effectiveOpacity() const void QGraphicsItem::setOpacity(qreal opacity) { // Notify change. -#ifndef QGRAPHICSITEM_NO_ITEMCHANGE const QVariant newOpacityVariant(itemChange(ItemOpacityChange, double(opacity))); qreal newOpacity = newOpacityVariant.toDouble(); -#else - qreal newOpacity = opacity; -#endif // Normalize. newOpacity = qBound(0.0, newOpacity, 1.0); @@ -2067,9 +2073,7 @@ void QGraphicsItem::setOpacity(qreal opacity) d_ptr->opacity = newOpacity; // Notify change. -#ifndef QGRAPHICSITEM_NO_ITEMCHANGE - itemChange(ItemOpacityHasChanged, newOpacity); -#endif + itemChange(ItemOpacityHasChanged, newOpacityVariant); // Update. if (d_ptr->scene) @@ -2508,42 +2512,33 @@ QPointF QGraphicsItem::scenePos() const /*! \internal - Sets the position \a pos and notifies the change. If \a update is true, - the item is also updated; otherwise it is not updated before and after the - change. + Sets the position \a pos. */ void QGraphicsItemPrivate::setPosHelper(const QPointF &pos) { Q_Q(QGraphicsItem); - if (this->pos == pos) - return; - - // Notify the item that the position is changing. -#ifndef QGRAPHICSITEM_NO_ITEMCHANGE - const QVariant newPosVariant(q->itemChange(QGraphicsItem::ItemPositionChange, pos)); - QPointF newPos = newPosVariant.toPointF(); - if (newPos == this->pos) - return; -#else - QPointF newPos = pos; -#endif - - // Update and repositition. inSetPosHelper = 1; - updateCachedClipPathFromSetPosHelper(newPos); + updateCachedClipPathFromSetPosHelper(pos); if (scene) q->prepareGeometryChange(); - this->pos = newPos; + this->pos = pos; dirtySceneTransform = 1; - - // Send post-notification. -#ifndef QGRAPHICSITEM_NO_ITEMCHANGE - q->itemChange(QGraphicsItem::ItemPositionHasChanged, newPosVariant); -#endif inSetPosHelper = 0; } /*! + \internal + + Sets the transform \a transform. +*/ +void QGraphicsItemPrivate::setTransformHelper(const QTransform &transform) +{ + q_ptr->prepareGeometryChange(); + transformData->transform = transform; + dirtySceneTransform = 1; +} + +/*! Sets the position of the item to \a pos, which is in parent coordinates. For items with no parent, \a pos is in scene coordinates. @@ -2555,7 +2550,26 @@ void QGraphicsItemPrivate::setPosHelper(const QPointF &pos) */ void QGraphicsItem::setPos(const QPointF &pos) { - d_ptr->setPosHelper(pos); + if (d_ptr->pos == pos) + return; + + // Update and repositition. + if (!(d_ptr->flags & ItemSendsGeometryChanges)) { + d_ptr->setPosHelper(pos); + return; + } + + // Notify the item that the position is changing. + const QVariant newPosVariant(itemChange(ItemPositionChange, qVariantFromValue(pos))); + QPointF newPos = newPosVariant.toPointF(); + if (newPos == d_ptr->pos) + return; + + // Update and repositition. + d_ptr->setPosHelper(newPos); + + // Send post-notification. + itemChange(QGraphicsItem::ItemPositionHasChanged, newPosVariant); } /*! @@ -3240,20 +3254,23 @@ void QGraphicsItem::setMatrix(const QMatrix &matrix, bool combine) if (d_ptr->transformData->transform == newTransform) return; + // Update and set the new transformation. + if (!(d_ptr->flags & ItemSendsGeometryChanges)) { + d_ptr->setTransformHelper(newTransform); + return; + } + // Notify the item that the transformation matrix is changing. - const QVariant newTransformVariant(itemChange(ItemTransformChange, - qVariantFromValue(newTransform))); - newTransform = qVariantValue(newTransformVariant); + const QVariant newMatrixVariant = qVariantFromValue(newTransform.toAffine()); + newTransform = QTransform(qVariantValue(itemChange(ItemMatrixChange, newMatrixVariant))); if (d_ptr->transformData->transform == newTransform) return; // Update and set the new transformation. - prepareGeometryChange(); - d_ptr->transformData->transform = newTransform; - d_ptr->dirtySceneTransform = 1; - + d_ptr->setTransformHelper(newTransform); + // Send post-notification. - itemChange(ItemTransformHasChanged, newTransformVariant); + itemChange(ItemTransformHasChanged, qVariantFromValue(newTransform)); } /*! @@ -3284,7 +3301,12 @@ void QGraphicsItem::setTransform(const QTransform &matrix, bool combine) if (d_ptr->transformData->transform == newTransform) return; - // Notify the item that the transformation matrix is changing. + // Update and set the new transformation. + if (!(d_ptr->flags & ItemSendsGeometryChanges)) { + d_ptr->setTransformHelper(newTransform); + return; + } + // Notify the item that the transformation matrix is changing. const QVariant newTransformVariant(itemChange(ItemTransformChange, qVariantFromValue(newTransform))); @@ -3293,9 +3315,7 @@ void QGraphicsItem::setTransform(const QTransform &matrix, bool combine) return; // Update and set the new transformation. - prepareGeometryChange(); - d_ptr->transformData->transform = newTransform; - d_ptr->dirtySceneTransform = 1; + d_ptr->setTransformHelper(newTransform); // Send post-notification. itemChange(ItemTransformHasChanged, newTransformVariant); @@ -9514,6 +9534,9 @@ QDebug operator<<(QDebug debug, QGraphicsItem::GraphicsItemFlag flag) case QGraphicsItem::ItemHasNoContents: str = "ItemHasNoContents"; break; + case QGraphicsItem::ItemSendsGeometryChanges: + str = "ItemSendsGeometryChanges"; + break; } debug << str; return debug; diff --git a/src/gui/graphicsview/qgraphicsitem.h b/src/gui/graphicsview/qgraphicsitem.h index 7e33c83..cff4f1f 100644 --- a/src/gui/graphicsview/qgraphicsitem.h +++ b/src/gui/graphicsview/qgraphicsitem.h @@ -96,7 +96,8 @@ public: ItemDoesntPropagateOpacityToChildren = 0x80, ItemStacksBehindParent = 0x100, ItemUsesExtendedStyleOption = 0x200, - ItemHasNoContents = 0x400 + ItemHasNoContents = 0x400, + ItemSendsGeometryChanges = 0x800 // NB! Don't forget to increase the d_ptr->flags bit field by 1 when adding a new flag. }; Q_DECLARE_FLAGS(GraphicsItemFlags, GraphicsItemFlag) diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index 13fee8f..e2a37a1 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -175,6 +175,7 @@ public: static bool movableAncestorIsSelected(const QGraphicsItem *item); void setPosHelper(const QPointF &pos); + void setTransformHelper(const QTransform &transform); void setVisibleHelper(bool newVisible, bool explicitly, bool update = true); void setEnabledHelper(bool newEnabled, bool explicitly, bool update = true); bool discardUpdateRequest(bool ignoreClipping = false, bool ignoreVisibleBit = false, @@ -397,12 +398,12 @@ public: quint32 fullUpdatePending : 1; // New 32 bits - quint32 flags : 11; + quint32 flags : 12; quint32 dirtyChildrenBoundingRect : 1; quint32 paintedViewBoundingRectsNeedRepaint : 1; quint32 dirtySceneTransform : 1; quint32 geometryChanged : 1; - quint32 unused : 17; // feel free to use + quint32 unused : 16; // feel free to use // Optional stacking order int globalStackingOrder; diff --git a/src/gui/graphicsview/qgraphicswidget.cpp b/src/gui/graphicsview/qgraphicswidget.cpp index 3296aee..7314167 100644 --- a/src/gui/graphicsview/qgraphicswidget.cpp +++ b/src/gui/graphicsview/qgraphicswidget.cpp @@ -1057,6 +1057,9 @@ void QGraphicsWidget::updateGeometry() ItemParentChange both to deliver \l ParentChange events, and for managing the focus chain. + QGraphicsWidget enables the ItemSendsGeometryChanges flag by default in + order to track position changes. + \sa propertyChange() */ QVariant QGraphicsWidget::itemChange(GraphicsItemChange change, const QVariant &value) diff --git a/src/gui/graphicsview/qgraphicswidget_p.cpp b/src/gui/graphicsview/qgraphicswidget_p.cpp index a435758..557b883 100644 --- a/src/gui/graphicsview/qgraphicswidget_p.cpp +++ b/src/gui/graphicsview/qgraphicswidget_p.cpp @@ -77,7 +77,9 @@ void QGraphicsWidgetPrivate::init(QGraphicsItem *parentItem, Qt::WindowFlags wFl resolveLayoutDirection(); q->unsetWindowFrameMargins(); q->setFlag(QGraphicsItem::ItemUsesExtendedStyleOption); + q->setFlag(QGraphicsItem::ItemSendsGeometryChanges); } + qreal QGraphicsWidgetPrivate::titleBarHeight(const QStyleOptionTitleBar &options) const { Q_Q(const QGraphicsWidget); diff --git a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp index c6f9824..d6ecbba 100644 --- a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp +++ b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp @@ -224,6 +224,7 @@ private slots: void setTransformProperties_data(); void setTransformProperties(); void itemUsesExtendedStyleOption(); + void itemSendsGeometryChanges(); void moveItem(); // task specific tests below me @@ -3730,8 +3731,20 @@ void tst_QGraphicsItem::defaultItemTest_QGraphicsEllipseItem() class ItemChangeTester : public QGraphicsRectItem { public: - ItemChangeTester(){} - ItemChangeTester(QGraphicsItem *parent) : QGraphicsRectItem(parent) {} + ItemChangeTester() + { setFlag(ItemSendsGeometryChanges); clear(); } + ItemChangeTester(QGraphicsItem *parent) : QGraphicsRectItem(parent) + { setFlag(ItemSendsGeometryChanges); clear(); } + + void clear() + { + itemChangeReturnValue = QVariant(); + itemSceneChangeTargetScene = 0; + changes.clear(); + values.clear(); + oldValues.clear(); + } + QVariant itemChangeReturnValue; QGraphicsScene *itemSceneChangeTargetScene; @@ -3932,7 +3945,8 @@ void tst_QGraphicsItem::itemChange() QCOMPARE(tester.changes.size(), changeCount); QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemFlagsChange); QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemFlagsHaveChanged); - QCOMPARE(tester.values.at(tester.values.size() - 2), qVariantFromValue(QGraphicsItem::ItemIsSelectable)); + QVariant expectedFlags = qVariantFromValue(QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemSendsGeometryChanges); + QCOMPARE(tester.values.at(tester.values.size() - 2), expectedFlags); QCOMPARE(tester.values.at(tester.values.size() - 1), qVariantFromValue(QGraphicsItem::ItemIsSelectable)); } { @@ -6745,6 +6759,44 @@ void tst_QGraphicsItem::itemUsesExtendedStyleOption() QTest::qWait(125); } +void tst_QGraphicsItem::itemSendsGeometryChanges() +{ + ItemChangeTester item; + item.setFlags(0); + item.clear(); + + QTransform x = QTransform().rotate(45); + QPointF pos(10, 10); + qreal o(0.5); + item.setTransform(x); + item.setPos(pos); + QCOMPARE(item.transform(), x); + QCOMPARE(item.pos(), pos); + QCOMPARE(item.changes.size(), 0); + + item.setOpacity(o); + QCOMPARE(item.changes.size(), 2); // opacity + + item.setFlag(QGraphicsItem::ItemSendsGeometryChanges); + QCOMPARE(item.changes.size(), 4); // flags + item.setTransform(QTransform()); + item.setPos(QPointF()); + QCOMPARE(item.changes.size(), 8); // transform + pos + QCOMPARE(item.transform(), QTransform()); + QCOMPARE(item.pos(), QPointF()); + QCOMPARE(item.opacity(), o); + + QCOMPARE(item.changes, QList() + << QGraphicsItem::ItemOpacityChange + << QGraphicsItem::ItemOpacityHasChanged + << QGraphicsItem::ItemFlagsChange + << QGraphicsItem::ItemFlagsHaveChanged + << QGraphicsItem::ItemTransformChange + << QGraphicsItem::ItemTransformHasChanged + << QGraphicsItem::ItemPositionChange + << QGraphicsItem::ItemPositionHasChanged); +} + // Make sure we update moved items correctly. void tst_QGraphicsItem::moveItem() { -- cgit v0.12 From e8be9f499547125490d61fb07b6aa023e38cd410 Mon Sep 17 00:00:00 2001 From: Andreas Aardal Hanssen Date: Mon, 8 Jun 2009 19:06:40 +0200 Subject: Update change log with behavior changes in Graphics View. --- dist/changes-4.6.0 | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/dist/changes-4.6.0 b/dist/changes-4.6.0 index bedf58a..ba58bcf 100644 --- a/dist/changes-4.6.0 +++ b/dist/changes-4.6.0 @@ -40,17 +40,30 @@ information about a particular change. reasons for this is that Qt Software focuses on OpenGL for desktop hardware accelerated rendering. - - QStyleOptionGraphicsItem::exposedRect and QStyleOptionGraphicsItem::matrix - does no longer contain fine-grained values when passed in drawItems()/paint() - unless the QGraphicsItem::ItemUsesExtendedStyleOptions flag is enabled. - By default, exposedRect is initialized to the item's bounding rect - and the matrix is untransformed. - - - QStyleOptionGraphicsItem::levelOfDetails is obsoleted and its value - is always initialized to 1. For a more fine-grained value use - QStyleOptionGraphicsItem::levelOfDetailFromTransform(const QTransform &). - - When mixing OpenGL and QPainter calls you need to first call syncState() on the paint engine, for example "painter->paintEngine()->syncState()". This is to ensure that the engine flushes any pending drawing and sets up the GL modelview/projection matrices properly. + + - Graphics View has undergone heavy optimization work, and as a result of + this work, the following behavior changes were introduced. + + a) QStyleOptionGraphicsItem::exposedRect now contains the item's bounding + rectangle, and QStyleOptionGraphicsItem::matrix is uninitialized by + default. You can enable an exact exposed rectangle and a correct matrix + by enabling the flag QGraphicsItem::ItemUsesExtendedStyleOptions. + + b) QStyleOptionGraphicsItem::levelOfDetails is obsoleted and its value is + always initialized to 1. Instead you can call + QStyleOptionGraphicsItem::levelOfDetailFromTransform(const QTransform &) + to determine the level of detail. + + c) QGraphicsView no longer calls QGraphicsView::drawItems(), and in turn + QGraphicsScene::drawItems(), by default. You can get the old behavior + back by enabling QGraphicsView::IndirectPainting. + + d) QGraphicsItem no longer calls itemChange() for position and + transformation changes. If you want to receive notifications for changes + to the item's position and transformation, you can set the flag + QGraphicsItem::ItemSendsGeometryChanges (which is enabled by default by + QGraphicsWidget and QGraphicsProxyWidget). -- cgit v0.12 From e2e039954b2212a9cee0b7f72e383621f8bc6c8f Mon Sep 17 00:00:00 2001 From: Andreas Aardal Hanssen Date: Mon, 8 Jun 2009 19:26:59 +0200 Subject: Revert 7aee2a7054d1ca280f6dfc9c46b3fe2ce403ccb3, fix render bugs. This change introduced an unexpected interdependency for scenes with items that enable ItemStacksBehindParent, and that contain children that are transformed. There's a manual test for this, called clippingAndTransformations, which shows this problem. The bug has been fixed and this change also includes an autotest that covers exactly this problem. --- src/gui/graphicsview/qgraphicsscene.cpp | 15 +++--- src/gui/graphicsview/qgraphicsscene_p.h | 1 - tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp | 72 ++++++++++++++++++++++---- 3 files changed, 70 insertions(+), 18 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index 7038c3d..7963ea1 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -5138,9 +5138,10 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * // Calculate the full transform for this item. QRect viewBoundingRect; bool wasDirtyParentSceneTransform = false; + QTransform transform; if (item) { if (item->d_ptr->itemIsUntransformable()) { - transformTmp = item->deviceTransform(viewTransform); + transform = item->deviceTransform(viewTransform); } else { if (item->d_ptr->dirtySceneTransform) { item->d_ptr->sceneTransform = item->d_ptr->parent ? item->d_ptr->parent->d_ptr->sceneTransform @@ -5149,14 +5150,14 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * item->d_ptr->dirtySceneTransform = 0; wasDirtyParentSceneTransform = true; } - transformTmp = item->d_ptr->sceneTransform; - transformTmp *= viewTransform; + transform = item->d_ptr->sceneTransform; + transform *= viewTransform; } QRectF brect = item->boundingRect(); // ### This does not take the clip into account. _q_adjustRect(&brect); - viewBoundingRect = transformTmp.mapRect(brect).toRect(); + viewBoundingRect = transform.mapRect(brect).toRect(); item->d_ptr->paintedViewBoundingRects.insert(widget, viewBoundingRect); viewBoundingRect.adjust(-1, -1, 1, 1); if (exposedRegion) @@ -5200,7 +5201,7 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * // Clip children. if (childClip) { painter->save(); - painter->setWorldTransform(transformTmp); + painter->setWorldTransform(transform); painter->setClipPath(item->shape(), Qt::IntersectClip); } @@ -5234,14 +5235,14 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * // Draw item if (!dontDrawItem) { - item->d_ptr->initStyleOption(&styleOptionTmp, transformTmp, exposedRegion ? *exposedRegion : QRegion(), exposedRegion == 0); + item->d_ptr->initStyleOption(&styleOptionTmp, transform, exposedRegion ? *exposedRegion : QRegion(), exposedRegion == 0); bool clipsToShape = (item->d_ptr->flags & QGraphicsItem::ItemClipsToShape); bool savePainter = clipsToShape || !(optimizationFlags & QGraphicsView::DontSavePainterState); if (savePainter) painter->save(); if (!childClip) - painter->setWorldTransform(transformTmp); + painter->setWorldTransform(transform); if (clipsToShape) painter->setClipPath(item->shape(), Qt::IntersectClip); painter->setOpacity(opacity); diff --git a/src/gui/graphicsview/qgraphicsscene_p.h b/src/gui/graphicsview/qgraphicsscene_p.h index fd7decf..000e2ba 100644 --- a/src/gui/graphicsview/qgraphicsscene_p.h +++ b/src/gui/graphicsview/qgraphicsscene_p.h @@ -290,7 +290,6 @@ public: void updatePalette(const QPalette &palette); QStyleOptionGraphicsItem styleOptionTmp; - QTransform transformTmp; }; QT_END_NAMESPACE diff --git a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp index d6ecbba..621f2bf 100644 --- a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp +++ b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp @@ -236,6 +236,9 @@ private slots: void task240400_clickOnTextItem(); void task243707_addChildBeforeParent(); void task197802_childrenVisibility(); + +private: + QList paintedItems; }; void tst_QGraphicsItem::init() @@ -5793,19 +5796,36 @@ void tst_QGraphicsItem::opacity2() QCOMPARE(grandChild->repaints, 0); } +class StacksBehindParentHelper : public QGraphicsRectItem +{ +public: + StacksBehindParentHelper(QList *paintedItems, const QRectF &rect, QGraphicsItem *parent = 0) + : QGraphicsRectItem(rect, parent), paintedItems(paintedItems) + { } + + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) + { + QGraphicsRectItem::paint(painter, option, widget); + paintedItems->append(this); + } + +private: + QList *paintedItems; +}; + void tst_QGraphicsItem::itemStacksBehindParent() { - QGraphicsRectItem *parent1 = new QGraphicsRectItem(QRectF(0, 0, 100, 50)); - QGraphicsRectItem *child11 = new QGraphicsRectItem(QRectF(-10, 10, 50, 50), parent1); - QGraphicsRectItem *grandChild111 = new QGraphicsRectItem(QRectF(-20, 20, 50, 50), child11); - QGraphicsRectItem *child12 = new QGraphicsRectItem(QRectF(60, 10, 50, 50), parent1); - QGraphicsRectItem *grandChild121 = new QGraphicsRectItem(QRectF(70, 20, 50, 50), child12); + StacksBehindParentHelper *parent1 = new StacksBehindParentHelper(&paintedItems, QRectF(0, 0, 100, 50)); + StacksBehindParentHelper *child11 = new StacksBehindParentHelper(&paintedItems, QRectF(-10, 10, 50, 50), parent1); + StacksBehindParentHelper *grandChild111 = new StacksBehindParentHelper(&paintedItems, QRectF(-20, 20, 50, 50), child11); + StacksBehindParentHelper *child12 = new StacksBehindParentHelper(&paintedItems, QRectF(60, 10, 50, 50), parent1); + StacksBehindParentHelper *grandChild121 = new StacksBehindParentHelper(&paintedItems, QRectF(70, 20, 50, 50), child12); - QGraphicsRectItem *parent2 = new QGraphicsRectItem(QRectF(0, 0, 100, 50)); - QGraphicsRectItem *child21 = new QGraphicsRectItem(QRectF(-10, 10, 50, 50), parent2); - QGraphicsRectItem *grandChild211 = new QGraphicsRectItem(QRectF(-20, 20, 50, 50), child21); - QGraphicsRectItem *child22 = new QGraphicsRectItem(QRectF(60, 10, 50, 50), parent2); - QGraphicsRectItem *grandChild221 = new QGraphicsRectItem(QRectF(70, 20, 50, 50), child22); + StacksBehindParentHelper *parent2 = new StacksBehindParentHelper(&paintedItems, QRectF(0, 0, 100, 50)); + StacksBehindParentHelper *child21 = new StacksBehindParentHelper(&paintedItems, QRectF(-10, 10, 50, 50), parent2); + StacksBehindParentHelper *grandChild211 = new StacksBehindParentHelper(&paintedItems, QRectF(-20, 20, 50, 50), child21); + StacksBehindParentHelper *child22 = new StacksBehindParentHelper(&paintedItems, QRectF(60, 10, 50, 50), parent2); + StacksBehindParentHelper *grandChild221 = new StacksBehindParentHelper(&paintedItems, QRectF(70, 20, 50, 50), child22); parent1->setData(0, "parent1"); child11->setData(0, "child11"); @@ -5827,25 +5847,57 @@ void tst_QGraphicsItem::itemStacksBehindParent() scene.addItem(parent1); scene.addItem(parent2); + paintedItems.clear(); + + QGraphicsView view(&scene); + view.show(); +#ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(&view); +#endif + QTest::qWait(250); + QCOMPARE(scene.items(0, 0, 100, 100), (QList() << grandChild111 << child11 << grandChild121 << child12 << parent1 << grandChild211 << child21 << grandChild221 << child22 << parent2)); + QCOMPARE(paintedItems, QList() + << parent2 << child22 << grandChild221 + << child21 << grandChild211 + << parent1 << child12 << grandChild121 + << child11 << grandChild111); child11->setFlag(QGraphicsItem::ItemStacksBehindParent); + scene.update(); + paintedItems.clear(); + QTest::qWait(250); + QCOMPARE(scene.items(0, 0, 100, 100), (QList() << grandChild121 << child12 << parent1 << grandChild111 << child11 << grandChild211 << child21 << grandChild221 << child22 << parent2)); + QCOMPARE(paintedItems, QList() + << parent2 << child22 << grandChild221 + << child21 << grandChild211 + << child11 << grandChild111 + << parent1 << child12 << grandChild121); child12->setFlag(QGraphicsItem::ItemStacksBehindParent); + paintedItems.clear(); + scene.update(); + QTest::qWait(250); + QCOMPARE(scene.items(0, 0, 100, 100), (QList() << parent1 << grandChild111 << child11 << grandChild121 << child12 << grandChild211 << child21 << grandChild221 << child22 << parent2)); + QCOMPARE(paintedItems, QList() + << parent2 << child22 << grandChild221 + << child21 << grandChild211 + << child12 << grandChild121 + << child11 << grandChild111 << parent1); } class ClippingAndTransformsScene : public QGraphicsScene -- cgit v0.12 From f84782506770f99e9633649483e4dd067e3abcd5 Mon Sep 17 00:00:00 2001 From: Andreas Aardal Hanssen Date: Mon, 8 Jun 2009 19:50:14 +0200 Subject: Fix QGraphicsView::render() regression, ensure the right device is passed. If we pass the viewport widget as the widget pointer when rendering to an arbitrary painter (e.g., onto a pixmap), we confuse the rendering functions to thinking that it's the viewport's region we should render into. So instead, when drawItems() is passed a painter that's different from the view, we pass 0 for the widget. --- src/gui/graphicsview/qgraphicsview.cpp | 6 ++- tests/auto/qgraphicsview/tst_qgraphicsview.cpp | 57 ++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 2 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp index 166bcb9..e685f9b 100644 --- a/src/gui/graphicsview/qgraphicsview.cpp +++ b/src/gui/graphicsview/qgraphicsview.cpp @@ -3526,8 +3526,10 @@ void QGraphicsView::drawItems(QPainter *painter, int numItems, const QStyleOptionGraphicsItem options[]) { Q_D(QGraphicsView); - if (d->scene) - d->scene->drawItems(painter, numItems, items, options, viewport()); + if (d->scene) { + QWidget *widget = painter->device() == viewport() ? viewport() : 0; + d->scene->drawItems(painter, numItems, items, options, widget); + } } /*! diff --git a/tests/auto/qgraphicsview/tst_qgraphicsview.cpp b/tests/auto/qgraphicsview/tst_qgraphicsview.cpp index 718c8d6..5167682 100644 --- a/tests/auto/qgraphicsview/tst_qgraphicsview.cpp +++ b/tests/auto/qgraphicsview/tst_qgraphicsview.cpp @@ -191,6 +191,7 @@ private slots: void centerOnDirtyItem(); void mouseTracking(); void mouseTracking2(); + void render(); // task specific tests below me void task172231_untransformableItems(); @@ -3203,6 +3204,62 @@ void tst_QGraphicsView::mouseTracking2() QCOMPARE(spy.count(), 1); } +class RenderTester : public QGraphicsRectItem +{ +public: + RenderTester(const QRectF &rect) + : QGraphicsRectItem(rect), paints(0) + { } + + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, + QWidget *widget) + { + QGraphicsRectItem::paint(painter, option, widget); + ++paints; + } + + int paints; +}; + +void tst_QGraphicsView::render() +{ + // ### This test can be much more thorough - see QGraphicsScene::render. + QGraphicsScene scene; + RenderTester *r1 = new RenderTester(QRectF(0, 0, 50, 50)); + RenderTester *r2 = new RenderTester(QRectF(50, 50, 50, 50)); + RenderTester *r3 = new RenderTester(QRectF(0, 50, 50, 50)); + RenderTester *r4 = new RenderTester(QRectF(50, 0, 50, 50)); + scene.addItem(r1); + scene.addItem(r2); + scene.addItem(r3); + scene.addItem(r4); + + QGraphicsView view(&scene); + view.setFrameStyle(0); + view.resize(200, 200); + view.show(); +#ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(&view); +#endif + QTest::qWait(200); + + QCOMPARE(r1->paints, 1); + QCOMPARE(r2->paints, 1); + QCOMPARE(r3->paints, 1); + QCOMPARE(r4->paints, 1); + + QPixmap pix(200, 200); + pix.fill(Qt::transparent); + QPainter painter(&pix); + view.render(&painter); + painter.end(); + + QCOMPARE(r1->paints, 2); + QCOMPARE(r2->paints, 2); + QCOMPARE(r3->paints, 2); + QCOMPARE(r4->paints, 2); +} + void tst_QGraphicsView::task253415_reconnectUpdateSceneOnSceneChanged() { QGraphicsView view; -- cgit v0.12 From 31fa814955cd2b0983b42543e133f24e9830c67f Mon Sep 17 00:00:00 2001 From: Andreas Aardal Hanssen Date: Mon, 8 Jun 2009 19:54:51 +0200 Subject: Fix moving regression for ItemIgnoresTransformations items. Removes a piece of code in 775ec8e96c9219981ff220ca5f3d24f0501d17b5 that was submitted by accident. The code in mouseMoveEvent is now identical to that in master. --- src/gui/graphicsview/qgraphicsitem.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index 3138faa..5ba87ee 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -5940,13 +5940,21 @@ void QGraphicsItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) if ((item->flags() & ItemIsMovable) && !QGraphicsItemPrivate::movableAncestorIsSelected(item)) { QPointF currentParentPos; QPointF buttonDownParentPos; - if (item->d_ptr->itemIsUntransformable()) { + if (item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorIgnoresTransformations) { // Items whose ancestors ignore transformations need to // map screen coordinates to local coordinates, then map // those to the parent. QTransform viewToItemTransform = (item->deviceTransform(view->viewportTransform())).inverted(); currentParentPos = mapToParent(viewToItemTransform.map(QPointF(view->mapFromGlobal(event->screenPos())))); buttonDownParentPos = mapToParent(viewToItemTransform.map(QPointF(view->mapFromGlobal(event->buttonDownScreenPos(Qt::LeftButton))))); + } else if (item->flags() & ItemIgnoresTransformations) { + // Root items that ignore transformations need to + // calculate their diff by mapping viewport coordinates + // directly to parent coordinates. + QTransform viewToParentTransform = (item->transform().translate(item->d_ptr->pos.x(), item->d_ptr->pos.y())) + * (item->sceneTransform() * view->viewportTransform()).inverted(); + currentParentPos = viewToParentTransform.map(QPointF(view->mapFromGlobal(event->screenPos()))); + buttonDownParentPos = viewToParentTransform.map(QPointF(view->mapFromGlobal(event->buttonDownScreenPos(Qt::LeftButton)))); } else { // All other items simply map from the scene. currentParentPos = item->mapToParent(item->mapFromScene(event->scenePos())); -- cgit v0.12 From e4d6cfb1be4a3ff71013362f1f827e3920524934 Mon Sep 17 00:00:00 2001 From: Andreas Aardal Hanssen Date: Tue, 9 Jun 2009 09:05:17 +0200 Subject: Ensure we use the correct static paintedItems list. Fixes the zValue autotest, which regressed when the member list was added. --- tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp index 621f2bf..af34fe5 100644 --- a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp +++ b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp @@ -1798,15 +1798,15 @@ void tst_QGraphicsItem::setMatrix() QCOMPARE(rlist.at(2), unrotatedRect); // From post-update (update current state) } -static QList paintedItems; +static QList _paintedItems; class PainterItem : public QGraphicsItem { protected: QRectF boundingRect() const { return QRectF(-10, -10, 20, 20); } - void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *) - { paintedItems << this; } + void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) + { _paintedItems << this; painter->fillRect(boundingRect(), Qt::red); } }; void tst_QGraphicsItem::zValue() @@ -1838,10 +1838,10 @@ void tst_QGraphicsItem::zValue() QApplication::sendPostedEvents(); //glib workaround #endif - QVERIFY(!paintedItems.isEmpty()); - QVERIFY((paintedItems.size() % 4) == 0); + QVERIFY(!_paintedItems.isEmpty()); + QVERIFY((_paintedItems.size() % 4) == 0); for (int i = 0; i < 3; ++i) - QVERIFY(paintedItems.at(i)->zValue() < paintedItems.at(i + 1)->zValue()); + QVERIFY(_paintedItems.at(i)->zValue() < _paintedItems.at(i + 1)->zValue()); } void tst_QGraphicsItem::shape() -- cgit v0.12 From 03428c4d2905cc73866f1d046b5cc1bedf1c38b3 Mon Sep 17 00:00:00 2001 From: Andreas Aardal Hanssen Date: Tue, 9 Jun 2009 09:05:57 +0200 Subject: Remove one unnecessary argument from the recursive draw function. We don't have to pass optimization flags; we already have a member variable we can test for painter state protection. --- src/gui/graphicsview/qgraphicsscene.cpp | 14 +++++--------- src/gui/graphicsview/qgraphicsscene_p.h | 2 +- src/gui/graphicsview/qgraphicsview.cpp | 2 +- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index 7963ea1..e43c9cd 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -5108,7 +5108,6 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter *painter, const QTransform &viewTransform, QRegion *exposedRegion, QWidget *widget, - QGraphicsView::OptimizationFlags optimizationFlags, QList *topLevelItems, qreal parentOpacity) { @@ -5229,7 +5228,7 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * if (!(child->d_ptr->flags & QGraphicsItem::ItemStacksBehindParent)) break; drawSubtreeRecursive(child, painter, viewTransform, exposedRegion, widget, - optimizationFlags, 0, opacity); + 0, opacity); } } @@ -5238,7 +5237,7 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * item->d_ptr->initStyleOption(&styleOptionTmp, transform, exposedRegion ? *exposedRegion : QRegion(), exposedRegion == 0); bool clipsToShape = (item->d_ptr->flags & QGraphicsItem::ItemClipsToShape); - bool savePainter = clipsToShape || !(optimizationFlags & QGraphicsView::DontSavePainterState); + bool savePainter = clipsToShape || painterStateProtection; if (savePainter) painter->save(); if (!childClip) @@ -5261,7 +5260,7 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * if (wasDirtyParentSceneTransform) child->d_ptr->dirtySceneTransform = 1; drawSubtreeRecursive(child, painter, viewTransform, exposedRegion, - widget, optimizationFlags, 0, opacity); + widget, 0, opacity); } } else if (wasDirtyParentSceneTransform) { item->d_ptr->invalidateChildrenSceneTransform(); @@ -5487,11 +5486,8 @@ void QGraphicsScene::drawItems(QPainter *painter, // Determine view, expose and flags. QGraphicsView *view = widget ? qobject_cast(widget->parentWidget()) : 0; QRegion *expose = 0; - QGraphicsView::OptimizationFlags flags; - if (view) { + if (view) expose = &view->d_func()->exposedRegion; - flags = view->optimizationFlags(); - } // Find all toplevels, they are already sorted. QList topLevelItems; @@ -5500,7 +5496,7 @@ void QGraphicsScene::drawItems(QPainter *painter, if (!item->d_ptr->itemDiscovered) { topLevelItems << item; item->d_ptr->itemDiscovered = 1; - d->drawSubtreeRecursive(item, painter, viewTransform, expose, widget, flags); + d->drawSubtreeRecursive(item, painter, viewTransform, expose, widget); } } diff --git a/src/gui/graphicsview/qgraphicsscene_p.h b/src/gui/graphicsview/qgraphicsscene_p.h index 000e2ba..42c4d8c 100644 --- a/src/gui/graphicsview/qgraphicsscene_p.h +++ b/src/gui/graphicsview/qgraphicsscene_p.h @@ -261,7 +261,7 @@ public: bool painterStateProtection); void drawSubtreeRecursive(QGraphicsItem *item, QPainter *painter, const QTransform &viewTransform, - QRegion *exposedRegion, QWidget *widget, QGraphicsView::OptimizationFlags optimizationFlags, + QRegion *exposedRegion, QWidget *widget, QList *topLevelItems = 0, qreal parentOpacity = qreal(1.0)); void markDirty(QGraphicsItem *item, const QRectF &rect = QRectF(), bool invalidateChildren = false, bool maybeDirtyClipPath = false, bool force = false, bool ignoreOpacity = false); diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp index e685f9b..4891e81 100644 --- a/src/gui/graphicsview/qgraphicsview.cpp +++ b/src/gui/graphicsview/qgraphicsview.cpp @@ -3303,7 +3303,7 @@ void QGraphicsView::paintEvent(QPaintEvent *event) // Items if (!(d->optimizationFlags & IndirectPainting)) { d->scene->d_func()->drawSubtreeRecursive(0, &painter, viewTransform, &d->exposedRegion, - viewport(), d->optimizationFlags, 0); + viewport(), 0); } else { // Find all exposed items bool allItems = false; -- cgit v0.12 From 662d1db6ee1a78c298acc11e7528e73c0415fc75 Mon Sep 17 00:00:00 2001 From: Martin Smith Date: Tue, 9 Jun 2009 10:32:20 +0200 Subject: doc: Corrected the rich text page wrt smallcaps. Task-number: 254912 --- doc/src/richtext.qdoc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/doc/src/richtext.qdoc b/doc/src/richtext.qdoc index fbd8adb..6ea82f8 100644 --- a/doc/src/richtext.qdoc +++ b/doc/src/richtext.qdoc @@ -1058,8 +1058,11 @@ Ideas for other sections: \o Specifies where an image or a text will be placed in another element. Note that the \c float property is only supported for tables and images. \row \o \c text-transform - \o [ uppercase | lowercase | smallcaps ] + \o [ uppercase | lowercase ] \o Select the transformation that will be performed on the text prior to displaying it. + \row \o \c font-variant + \o small-caps + \o Perform the smallcaps transformation on the text prior to displaying it. \row \o \c word-spacing \o px \o Specifies an alternate spacing between each word. -- cgit v0.12 From 91ceb21d1d5f6447a47853b6625fb51d2f21cf16 Mon Sep 17 00:00:00 2001 From: Thierry Bastian Date: Tue, 9 Jun 2009 10:51:26 +0200 Subject: small refactoring to reduce memory usage of static data --- src/corelib/codecs/qisciicodec.cpp | 2 +- src/corelib/tools/qlocale.cpp | 2 +- src/corelib/tools/qlocale_data_p.h | 10 +++++----- src/corelib/xml/qxmlstream.cpp | 7 +++---- util/local_database/qlocalexml2cpp.py | 6 +++--- 5 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/corelib/codecs/qisciicodec.cpp b/src/corelib/codecs/qisciicodec.cpp index dd2bc8d..de1e477 100644 --- a/src/corelib/codecs/qisciicodec.cpp +++ b/src/corelib/codecs/qisciicodec.cpp @@ -55,7 +55,7 @@ QT_BEGIN_NAMESPACE struct Codecs { - const char *name; + const char name[10]; ushort base; }; diff --git a/src/corelib/tools/qlocale.cpp b/src/corelib/tools/qlocale.cpp index 00132d7..4898e10 100644 --- a/src/corelib/tools/qlocale.cpp +++ b/src/corelib/tools/qlocale.cpp @@ -772,7 +772,7 @@ QVariant QSystemLocale::query(QueryType type, QVariant in = QVariant()) const Instead it can return a "Windows code". This maps windows codes to ISO country names. */ struct WindowsToISOListElt { - int windows_code; + ushort windows_code; char iso_name[6]; }; diff --git a/src/corelib/tools/qlocale_data_p.h b/src/corelib/tools/qlocale_data_p.h index 37f59a4..e0eecf3 100644 --- a/src/corelib/tools/qlocale_data_p.h +++ b/src/corelib/tools/qlocale_data_p.h @@ -60,8 +60,8 @@ QT_BEGIN_NAMESPACE */ struct CountryLanguage { - quint32 languageId; - quint32 countryId; + quint16 languageId; + quint16 countryId; }; static const CountryLanguage ImperialMeasurementSystems[] = { { 31, 225 }, @@ -83,7 +83,7 @@ static const int ImperialMeasurementSystemsCount = */ -static const uint locale_index[] = { +static const quint16 locale_index[] = { 0, // unused 0, // C 0, // Abkhazian @@ -2313,7 +2313,7 @@ static const char language_name_list[] = "Chewa\0" ; -static const uint language_name_index[] = { +static const quint16 language_name_index[] = { 0, // Unused 8, // C 10, // Abkhazian @@ -2727,7 +2727,7 @@ static const char country_name_list[] = "SerbiaAndMontenegro\0" ; -static const uint country_name_index[] = { +static const quint16 country_name_index[] = { 0, // AnyCountry 8, // Afghanistan 20, // Albania diff --git a/src/corelib/xml/qxmlstream.cpp b/src/corelib/xml/qxmlstream.cpp index 5e1fec3..fddcecf 100644 --- a/src/corelib/xml/qxmlstream.cpp +++ b/src/corelib/xml/qxmlstream.cpp @@ -629,7 +629,7 @@ while () { $sizes[$i++] = $counter; $counter += length 1 + $_; } -print " \"\\0\";\n\nstatic const int QXmlStreamReader_tokenTypeString_indices[] = {\n "; +print " \"\\0\";\n\nstatic const short QXmlStreamReader_tokenTypeString_indices[] = {\n "; for ($j = 0; $j < $i; ++$j) { printf "$sizes[$j], "; } @@ -660,10 +660,9 @@ static const char QXmlStreamReader_tokenTypeString_string[] = "Comment\0" "DTD\0" "EntityReference\0" - "ProcessingInstruction\0" - "\0"; + "ProcessingInstruction\0"; -static const int QXmlStreamReader_tokenTypeString_indices[] = { +static const short QXmlStreamReader_tokenTypeString_indices[] = { 0, 8, 16, 30, 42, 55, 66, 77, 85, 89, 105, 0 }; diff --git a/util/local_database/qlocalexml2cpp.py b/util/local_database/qlocalexml2cpp.py index af6da33..d625cfd 100755 --- a/util/local_database/qlocalexml2cpp.py +++ b/util/local_database/qlocalexml2cpp.py @@ -318,7 +318,7 @@ def main(): print # Locale index - print "static const uint locale_index[] = {" + print "static const quint16 locale_index[] = {" print " 0, // unused" index = 0 for key in language_map.keys(): @@ -454,7 +454,7 @@ def main(): print # Language name index - print "static const uint language_name_index[] = {" + print "static const quint16 language_name_index[] = {" print " 0, // Unused" index = 8 for key in language_map.keys(): @@ -477,7 +477,7 @@ def main(): print # Country name index - print "static const uint country_name_index[] = {" + print "static const quint16 country_name_index[] = {" print " 0, // AnyCountry" index = 8 for key in country_map.keys(): -- cgit v0.12 From b1658783099b75097f02bef85c4ea2a469826d37 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Thu, 4 Jun 2009 19:49:41 +0200 Subject: make bic test works in shadow build --- tests/auto/bic/bic.pro | 6 ++++++ tests/auto/bic/tst_bic.cpp | 33 +++++++++++++++++---------------- 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/tests/auto/bic/bic.pro b/tests/auto/bic/bic.pro index a168d77..82711c9 100644 --- a/tests/auto/bic/bic.pro +++ b/tests/auto/bic/bic.pro @@ -2,3 +2,9 @@ load(qttest_p4) SOURCES += tst_bic.cpp qbic.cpp QT = core +wince*:{ + DEFINES += SRCDIR=\\\"\\\" +} else { + DEFINES += SRCDIR=\\\"$$PWD/\\\" +} + diff --git a/tests/auto/bic/tst_bic.cpp b/tests/auto/bic/tst_bic.cpp index 181c275..8bc8d4f 100644 --- a/tests/auto/bic/tst_bic.cpp +++ b/tests/auto/bic/tst_bic.cpp @@ -165,30 +165,30 @@ void tst_Bic::sizesAndVTables_data() #if defined Q_OS_LINUX && defined Q_WS_X11 # if defined(__powerpc__) && !defined(__powerpc64__) - archFileName400 = "data/%1.4.0.0.linux-gcc-ppc32.txt"; - archFileName410 = "data/%1.4.1.0.linux-gcc-ppc32.txt"; - archFileName420 = "data/%1.4.2.0.linux-gcc-ppc32.txt"; + archFileName400 = SRCDIR "data/%1.4.0.0.linux-gcc-ppc32.txt"; + archFileName410 = SRCDIR "data/%1.4.1.0.linux-gcc-ppc32.txt"; + archFileName420 = SRCDIR "data/%1.4.2.0.linux-gcc-ppc32.txt"; # elif defined(__amd64__) - archFileName400 = "data/%1.4.0.0.linux-gcc-amd64.txt"; + archFileName400 = SRCDIR "data/%1.4.0.0.linux-gcc-amd64.txt"; # elif defined(__i386__) - archFileName400 = "data/%1.4.0.0.linux-gcc-ia32.txt"; - archFileName410 = "data/%1.4.1.0.linux-gcc-ia32.txt"; - archFileName420 = "data/%1.4.2.0.linux-gcc-ia32.txt"; - archFileName430 = "data/%1.4.3.0.linux-gcc-ia32.txt"; + archFileName400 = SRCDIR "data/%1.4.0.0.linux-gcc-ia32.txt"; + archFileName410 = SRCDIR "data/%1.4.1.0.linux-gcc-ia32.txt"; + archFileName420 = SRCDIR "data/%1.4.2.0.linux-gcc-ia32.txt"; + archFileName430 = SRCDIR "data/%1.4.3.0.linux-gcc-ia32.txt"; # endif #elif defined Q_OS_AIX if (sizeof(void*) == 4) - archFileName400 = "data/%1.4.0.0.aix-gcc-power32.txt"; + archFileName400 = SRCDIR "data/%1.4.0.0.aix-gcc-power32.txt"; #elif defined Q_OS_MAC && defined(__powerpc__) - archFileName400 = "data/%1.4.0.0.macx-gcc-ppc32.txt"; - archFileName410 = "data/%1.4.1.0.macx-gcc-ppc32.txt"; - archFileName420 = "data/%1.4.2.0.macx-gcc-ppc32.txt"; + archFileName400 = SRCDIR "data/%1.4.0.0.macx-gcc-ppc32.txt"; + archFileName410 = SRCDIR "data/%1.4.1.0.macx-gcc-ppc32.txt"; + archFileName420 = SRCDIR "data/%1.4.2.0.macx-gcc-ppc32.txt"; #elif defined Q_OS_MAC && defined(__i386__) - archFileName410 = "data/%1.4.1.0.macx-gcc-ia32.txt"; - archFileName420 = "data/%1.4.2.0.macx-gcc-ia32.txt"; + archFileName410 = SRCDIR "data/%1.4.1.0.macx-gcc-ia32.txt"; + archFileName420 = SRCDIR "data/%1.4.2.0.macx-gcc-ia32.txt"; #elif defined Q_OS_WIN && defined Q_CC_GNU - archFileName410 = "data/%1.4.1.0.win32-gcc-ia32.txt"; - archFileName420 = "data/%1.4.2.0.win32-gcc-ia32.txt"; + archFileName410 = SRCDIR "data/%1.4.1.0.win32-gcc-ia32.txt"; + archFileName420 = SRCDIR "data/%1.4.2.0.win32-gcc-ia32.txt"; #endif if (archFileName400.isEmpty() && archFileName410.isEmpty() @@ -293,6 +293,7 @@ void tst_Bic::sizesAndVTables() bool isFailed = false; + qDebug() << oldLib.arg(libName); if (oldLib.isEmpty() || !QFile::exists(oldLib.arg(libName))) QSKIP("No platform spec found for this platform/version.", SkipSingle); -- cgit v0.12 From c5a9996213a535ad6b1e183ed258913082213073 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Tue, 9 Jun 2009 11:10:46 +0200 Subject: Fix focus frame on combobox on non-Windows styles State_KeyboardFocusChange only makes sens on Windows. Follow the logic on the combobox as in PE_FrameFocusRect in the QWindowsStyle Task-number: 255482 Reviewed-by: jbache --- src/gui/styles/qcleanlooksstyle.cpp | 3 ++- src/gui/styles/qgtkstyle.cpp | 2 +- src/gui/styles/qplastiquestyle.cpp | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/gui/styles/qcleanlooksstyle.cpp b/src/gui/styles/qcleanlooksstyle.cpp index b33dfc1..805cd05 100644 --- a/src/gui/styles/qcleanlooksstyle.cpp +++ b/src/gui/styles/qcleanlooksstyle.cpp @@ -3305,7 +3305,8 @@ void QCleanlooksStyle::drawComplexControl(ComplexControl control, const QStyleOp } } // Draw the focus rect - if ((focus && (option->state & State_KeyboardFocusChange)) && !comboBox->editable) { + if (focus && !comboBox->editable + && ((option->state & State_KeyboardFocusChange) || styleHint(SH_UnderlineShortcut, option, widget))) { QStyleOptionFocusRect focus; focus.rect = subControlRect(CC_ComboBox, &comboBoxCopy, SC_ComboBoxEditField, widget) .adjusted(0, 2, option->direction == Qt::RightToLeft ? 1 : -1, -2); diff --git a/src/gui/styles/qgtkstyle.cpp b/src/gui/styles/qgtkstyle.cpp index 1fe4627..ab81d97 100644 --- a/src/gui/styles/qgtkstyle.cpp +++ b/src/gui/styles/qgtkstyle.cpp @@ -1426,7 +1426,7 @@ void QGtkStyle::drawComplexControl(ComplexControl control, const QStyleOptionCom QGtk::gtk_widget_style_get(gtkToggleButton, "interior-focus", &interiorFocus, NULL); int xt = interiorFocus ? gtkToggleButton->style->xthickness : 0; int yt = interiorFocus ? gtkToggleButton->style->ythickness : 0; - if ((focus && (option->state & State_KeyboardFocusChange))) + if (focus && ((option->state & State_KeyboardFocusChange) || styleHint(SH_UnderlineShortcut, option, widget))) gtkCachedPainter.paintFocus(gtkToggleButton, "button", option->rect.adjusted(xt, yt, -xt, -yt), option->state & State_Sunken ? GTK_STATE_ACTIVE : GTK_STATE_NORMAL, diff --git a/src/gui/styles/qplastiquestyle.cpp b/src/gui/styles/qplastiquestyle.cpp index 01c0e44..0a56213 100644 --- a/src/gui/styles/qplastiquestyle.cpp +++ b/src/gui/styles/qplastiquestyle.cpp @@ -4568,7 +4568,8 @@ void QPlastiqueStyle::drawComplexControl(ComplexControl control, const QStyleOpt } // Draw the focus rect - if (((option->state & State_HasFocus) && (option->state & State_KeyboardFocusChange)) && !comboBox->editable) { + if ((option->state & State_HasFocus) && !comboBox->editable + && ((option->state & State_KeyboardFocusChange) || styleHint(SH_UnderlineShortcut, option, widget))) { QStyleOptionFocusRect focus; focus.rect = subControlRect(CC_ComboBox, option, SC_ComboBoxEditField, widget) .adjusted(-2, 0, 2, 0); -- cgit v0.12 From 9b88c6f485016b53d394a88106a048495cf79294 Mon Sep 17 00:00:00 2001 From: Leonardo Sobral Cunha Date: Tue, 9 Jun 2009 11:58:45 +0200 Subject: Fix QImageReader autotest compilation --- tests/auto/qimagereader/qimagereader.qrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/auto/qimagereader/qimagereader.qrc b/tests/auto/qimagereader/qimagereader.qrc index 3c674ad..c6b963b 100644 --- a/tests/auto/qimagereader/qimagereader.qrc +++ b/tests/auto/qimagereader/qimagereader.qrc @@ -30,7 +30,7 @@ images/image.pgm images/image.png images/image.ppm - images/image.tif + images/image_100dpi.tif images/kollada.png images/marble.xpm images/namedcolors.xpm -- cgit v0.12 From d826a08add652314bb22bee44e0d43bbd672f272 Mon Sep 17 00:00:00 2001 From: Leonardo Sobral Cunha Date: Tue, 9 Jun 2009 12:02:59 +0200 Subject: Fix floating point exception in QImageReader::setScaledSize(QSize(0, 0)) Avoid a division by 0 when doing QImageReader::setScaledSize(QSize(0, 0)) for jpeg formats. Reviewed-by: thierry Task-number: 255627 --- src/plugins/imageformats/jpeg/qjpeghandler.cpp | 3 ++- tests/auto/qimagereader/tst_qimagereader.cpp | 26 ++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/plugins/imageformats/jpeg/qjpeghandler.cpp b/src/plugins/imageformats/jpeg/qjpeghandler.cpp index 6d0bc1f..088ef97 100644 --- a/src/plugins/imageformats/jpeg/qjpeghandler.cpp +++ b/src/plugins/imageformats/jpeg/qjpeghandler.cpp @@ -781,7 +781,8 @@ static bool read_jpeg_image(QIODevice *device, QImage *outImage, #ifndef QT_NO_IMAGE_SMOOTHSCALE // If high quality not required, shrink image during decompression - if (scaledSize.isValid() && quality < HIGH_QUALITY_THRESHOLD && !params.contains(QLatin1String("GetHeaderInformation")) ) { + if (scaledSize.isValid() && !scaledSize.isEmpty() && quality < HIGH_QUALITY_THRESHOLD + && !params.contains(QLatin1String("GetHeaderInformation")) ) { cinfo.scale_denom = qMin(cinfo.image_width / scaledSize.width(), cinfo.image_width / scaledSize.height()); if (cinfo.scale_denom < 2) { diff --git a/tests/auto/qimagereader/tst_qimagereader.cpp b/tests/auto/qimagereader/tst_qimagereader.cpp index f5313eb..0b32f0a 100644 --- a/tests/auto/qimagereader/tst_qimagereader.cpp +++ b/tests/auto/qimagereader/tst_qimagereader.cpp @@ -156,6 +156,9 @@ private slots: void pixelCompareWithBaseline_data(); void pixelCompareWithBaseline(); + + void task255627_setNullScaledSize_data(); + void task255627_setNullScaledSize(); }; static const QLatin1String prefix(SRCDIR "/images/"); @@ -333,6 +336,29 @@ void tst_QImageReader::setScaledSize() QCOMPARE(image.size(), newSize); } +void tst_QImageReader::task255627_setNullScaledSize_data() +{ + setScaledSize_data(); +} + +void tst_QImageReader::task255627_setNullScaledSize() +{ + QFETCH(QString, fileName); + QFETCH(QByteArray, format); + + if (!format.isEmpty() && !QImageReader::supportedImageFormats().contains(format)) + QSKIP("Qt does not support reading the \"" + format + "\" format", SkipSingle); + + QImageReader reader(prefix + fileName); + + // set a null size + reader.setScaledSize(QSize(0, 0)); + reader.setQuality(0); + QImage image = reader.read(); + QVERIFY(image.isNull()); + QCOMPARE(image.size(), QSize(0, 0)); +} + void tst_QImageReader::setClipRect_data() { QTest::addColumn("fileName"); -- cgit v0.12 From 2de2018a33ea45b32963378bb4f7ef24cd181485 Mon Sep 17 00:00:00 2001 From: Kent Hansen Date: Tue, 9 Jun 2009 12:32:05 +0200 Subject: WinCE doesn't have time() function, use QTime --- examples/statemachine/tankgameplugins/random_ai/random_ai_plugin.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/examples/statemachine/tankgameplugins/random_ai/random_ai_plugin.cpp b/examples/statemachine/tankgameplugins/random_ai/random_ai_plugin.cpp index d360de9..2368608 100644 --- a/examples/statemachine/tankgameplugins/random_ai/random_ai_plugin.cpp +++ b/examples/statemachine/tankgameplugins/random_ai/random_ai_plugin.cpp @@ -42,13 +42,12 @@ #include "random_ai_plugin.h" #include +#include #include -#include - QState *RandomAiPlugin::create(QState *parentState, QObject *tank) { - qsrand(uint(time(NULL))); + qsrand(QTime(0,0,0).secsTo(QTime::currentTime())); QState *topLevel = new QState(parentState); -- cgit v0.12 From d6f171c9baa61858aea0db36fd8b1bd3219ffd0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Fri, 5 Jun 2009 11:47:32 +0200 Subject: Improved clipping in GL2 paint engine. Use the stencil method to draw clip paths and regions to the Z-buffer instead of using glClear / glScissor. Using different depth values for the various clip parts also makes restore() very cheap when only IntersectClip is used. As an additional bonus this patch gives antialiased clip in the GL 2 paint engine. Task-number: 254658 Reviewed-by: Trond --- src/gui/painting/qpaintengineex.cpp | 80 ++++- src/gui/painting/qpaintengineex_p.h | 32 +- src/gui/painting/qpainter.h | 1 + .../gl2paintengineex/qglengineshadermanager.cpp | 3 +- .../gl2paintengineex/qglengineshadersource_p.h | 14 + .../gl2paintengineex/qpaintengineex_opengl2.cpp | 374 ++++++++++++--------- .../gl2paintengineex/qpaintengineex_opengl2_p.h | 25 +- 7 files changed, 343 insertions(+), 186 deletions(-) diff --git a/src/gui/painting/qpaintengineex.cpp b/src/gui/painting/qpaintengineex.cpp index 28f9220..3cf5ff9 100644 --- a/src/gui/painting/qpaintengineex.cpp +++ b/src/gui/painting/qpaintengineex.cpp @@ -138,6 +138,76 @@ QPaintEngineExPrivate::~QPaintEngineExPrivate() } +void QPaintEngineExPrivate::replayClipOperations() +{ + Q_Q(QPaintEngineEx); + + QPainter *p = q->painter(); + if (!p || !p->d_ptr) + return; + + QPainterPrivate *pp = p->d_ptr; + QList clipInfo = pp->state->clipInfo; + + QTransform transform = q->state()->matrix; + + QTransform redirection; + redirection.translate(-q->state()->redirection_offset.x(), -q->state()->redirection_offset.y()); + + for (int i = 0; i < clipInfo.size(); ++i) { + const QPainterClipInfo &info = clipInfo.at(i); + + QTransform combined = info.matrix * redirection; + + if (combined != q->state()->matrix) { + q->state()->matrix = combined; + q->transformChanged(); + } + + switch (info.clipType) { + case QPainterClipInfo::RegionClip: + q->clip(info.region, info.operation); + break; + case QPainterClipInfo::PathClip: + q->clip(info.path, info.operation); + break; + case QPainterClipInfo::RectClip: + q->clip(info.rect, info.operation); + break; + case QPainterClipInfo::RectFClip: { + qreal right = info.rectf.x() + info.rectf.width(); + qreal bottom = info.rectf.y() + info.rectf.height(); + qreal pts[] = { info.rectf.x(), info.rectf.y(), + right, info.rectf.y(), + right, bottom, + info.rectf.x(), bottom }; + QVectorPath vp(pts, 4, 0, QVectorPath::RectangleHint); + q->clip(vp, info.operation); + break; + } + } + } + + if (transform != q->state()->matrix) { + q->state()->matrix = transform; + q->transformChanged(); + } +} + + +bool QPaintEngineExPrivate::hasClipOperations() const +{ + Q_Q(const QPaintEngineEx); + + QPainter *p = q->painter(); + if (!p || !p->d_ptr) + return false; + + QPainterPrivate *pp = p->d_ptr; + QList clipInfo = pp->state->clipInfo; + + return !clipInfo.isEmpty(); +} /******************************************************************************* * @@ -244,13 +314,18 @@ static void qpaintengineex_cubicTo(qreal c1x, qreal c1y, qreal c2x, qreal c2y, q ((StrokeHandler *) data)->types.add(QPainterPath::CurveToDataElement); } +QPaintEngineEx::QPaintEngineEx() + : QPaintEngine(*new QPaintEngineExPrivate, AllFeatures) +{ + extended = true; +} + QPaintEngineEx::QPaintEngineEx(QPaintEngineExPrivate &data) : QPaintEngine(data, AllFeatures) { extended = true; } - QPainterState *QPaintEngineEx::createState(QPainterState *orig) const { if (!orig) @@ -483,6 +558,9 @@ void QPaintEngineEx::clip(const QRect &r, Qt::ClipOperation op) void QPaintEngineEx::clip(const QRegion ®ion, Qt::ClipOperation op) { + if (region.numRects() == 1) + clip(region.boundingRect(), op); + QVector rects = region.rects(); if (rects.size() <= 32) { qreal pts[2*32*4]; diff --git a/src/gui/painting/qpaintengineex_p.h b/src/gui/painting/qpaintengineex_p.h index 1c55242..3f64260 100644 --- a/src/gui/painting/qpaintengineex_p.h +++ b/src/gui/painting/qpaintengineex_p.h @@ -139,27 +139,13 @@ public: QDebug Q_GUI_EXPORT &operator<<(QDebug &, const QVectorPath &path); #endif -class Q_GUI_EXPORT QPaintEngineExPrivate : public QPaintEnginePrivate -{ -public: - QPaintEngineExPrivate(); - ~QPaintEngineExPrivate(); - - QStroker stroker; - QDashStroker dasher; - StrokeHandler *strokeHandler; - QStrokerOps *activeStroker; - QPen strokerPen; -}; - class QPixmapFilter; class Q_GUI_EXPORT QPaintEngineEx : public QPaintEngine { Q_DECLARE_PRIVATE(QPaintEngineEx) public: - inline QPaintEngineEx() - : QPaintEngine(*new QPaintEngineExPrivate, AllFeatures) { extended = true; } + QPaintEngineEx(); virtual QPainterState *createState(QPainterState *orig) const; @@ -224,6 +210,22 @@ protected: QPaintEngineEx(QPaintEngineExPrivate &data); }; +class Q_GUI_EXPORT QPaintEngineExPrivate : public QPaintEnginePrivate +{ + Q_DECLARE_PUBLIC(QPaintEngineEx) +public: + QPaintEngineExPrivate(); + ~QPaintEngineExPrivate(); + + void replayClipOperations(); + bool hasClipOperations() const; + + QStroker stroker; + QDashStroker dasher; + StrokeHandler *strokeHandler; + QStrokerOps *activeStroker; + QPen strokerPen; +}; inline uint QVectorPath::polygonFlags(QPaintEngine::PolygonDrawMode mode) { switch (mode) { diff --git a/src/gui/painting/qpainter.h b/src/gui/painting/qpainter.h index f3df7a3..78cd713 100644 --- a/src/gui/painting/qpainter.h +++ b/src/gui/painting/qpainter.h @@ -507,6 +507,7 @@ private: friend class QFontEngineXLFD; friend class QWSManager; friend class QPaintEngine; + friend class QPaintEngineExPrivate; friend class QOpenGLPaintEngine; friend class QX11PaintEngine; friend class QX11PaintEnginePrivate; diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp index ea57fdf..5c541d0 100644 --- a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp +++ b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp @@ -157,6 +157,7 @@ QGLEngineShaderManager::QGLEngineShaderManager(QGLContext* context) simpleShaderProg->addShader(compiledShaders[PositionOnlyVertexShader]); simpleShaderProg->addShader(compiledShaders[MainFragmentShader]); simpleShaderProg->addShader(compiledShaders[ShockingPinkSrcFragmentShader]); + simpleShaderProg->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR); simpleShaderProg->link(); if (!simpleShaderProg->isLinked()) { qCritical() << "Errors linking simple shader:" @@ -444,7 +445,7 @@ bool QGLEngineShaderManager::useCorrectShaderProg() requiredProgram.program->addShader(requiredProgram.compositionFragShader); // We have to bind the vertex attribute names before the program is linked: - requiredProgram.program->bindAttributeLocation("inputVertex", QT_VERTEX_COORDS_ATTR); + requiredProgram.program->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR); if (useTextureCoords) requiredProgram.program->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR); diff --git a/src/opengl/gl2paintengineex/qglengineshadersource_p.h b/src/opengl/gl2paintengineex/qglengineshadersource_p.h index 920d0bc..70cc67e 100644 --- a/src/opengl/gl2paintengineex/qglengineshadersource_p.h +++ b/src/opengl/gl2paintengineex/qglengineshadersource_p.h @@ -84,16 +84,20 @@ static const char* const qglslMainWithTexCoordsVertexShader = "\ static const char* const qglslPositionOnlyVertexShader = "\ attribute highp vec4 vertexCoordsArray;\ uniform highp mat4 pmvMatrix;\ + uniform highp float depth;\ void setPosition(void)\ {\ gl_Position = pmvMatrix * vertexCoordsArray;\ + gl_Position.z = depth;\ }"; static const char* const qglslUntransformedPositionVertexShader = "\ attribute highp vec4 vertexCoordsArray;\ + uniform highp float depth;\ void setPosition(void)\ {\ gl_Position = vertexCoordsArray;\ + gl_Position.z = depth;\ }"; // Pattern Brush - This assumes the texture size is 8x8 and thus, the inverted size is 0.125 @@ -104,9 +108,11 @@ static const char* const qglslPositionWithPatternBrushVertexShader = "\ uniform mediump vec2 invertedTextureSize; \ uniform mediump mat3 brushTransform; \ varying mediump vec2 patternTexCoords; \ + uniform highp float depth;\ void setPosition(void) { \ gl_Position = pmvMatrix * vertexCoordsArray;\ gl_Position.xy = gl_Position.xy / gl_Position.w; \ + gl_Position.z = depth;\ mediump vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \ mediump vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1); \ mediump float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \ @@ -136,9 +142,11 @@ static const char* const qglslPositionWithLinearGradientBrushVertexShader = "\ uniform highp vec3 linearData; \ uniform highp mat3 brushTransform; \ varying mediump float index ; \ + uniform highp float depth;\ void setPosition() { \ gl_Position = pmvMatrix * vertexCoordsArray;\ gl_Position.xy = gl_Position.xy / gl_Position.w; \ + gl_Position.z = depth;\ mediump vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \ mediump vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1); \ mediump float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \ @@ -166,10 +174,12 @@ static const char* const qglslPositionWithConicalGradientBrushVertexShader = "\ uniform mediump vec2 halfViewportSize; \ uniform highp mat3 brushTransform; \ varying highp vec2 A; \ + uniform highp float depth;\ void setPosition(void)\ {\ gl_Position = pmvMatrix * vertexCoordsArray;\ gl_Position.xy = gl_Position.xy / gl_Position.w; \ + gl_Position.z = depth; \ mediump vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \ mediump vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1); \ mediump float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \ @@ -205,10 +215,12 @@ static const char* const qglslPositionWithRadialGradientBrushVertexShader = "\ uniform highp vec2 fmp; \ varying highp float b; \ varying highp vec2 A; \ + uniform highp float depth;\ void setPosition(void) \ {\ gl_Position = pmvMatrix * vertexCoordsArray;\ gl_Position.xy = gl_Position.xy / gl_Position.w; \ + gl_Position.z = depth; \ mediump vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \ mediump vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1); \ mediump float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \ @@ -242,9 +254,11 @@ static const char* const qglslPositionWithTextureBrushVertexShader = "\ uniform mediump vec2 invertedTextureSize; \ uniform mediump mat3 brushTransform; \ varying mediump vec2 brushTextureCoords; \ + uniform highp float depth;\ void setPosition(void) { \ gl_Position = pmvMatrix * vertexCoordsArray;\ gl_Position.xy = gl_Position.xy / gl_Position.w; \ + gl_Position.z = depth; \ mediump vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \ mediump vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1); \ mediump float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \ diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index 868adcf..fae3045 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -183,8 +183,8 @@ void QGLTextureGlyphCache::resizeTextureData(int width, int height) pex->transferMode(BrushDrawingMode); - glDisable(GL_SCISSOR_TEST); glDisable(GL_DEPTH_TEST); + glDisable(GL_SCISSOR_TEST); glViewport(0, 0, oldWidth, oldHeight); @@ -217,7 +217,7 @@ void QGLTextureGlyphCache::resizeTextureData(int width, int height) glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->d_ptr->current_fbo); glViewport(0, 0, pex->width, pex->height); - pex->updateDepthClip(); + pex->updateDepthScissorTest(); } void QGLTextureGlyphCache::fillTexture(const Coord &c, glyph_t glyph) @@ -297,6 +297,11 @@ void QGL2PaintEngineExPrivate::useSimpleShader() shaderManager->simpleProgram()->setUniformValue("pmvMatrix", pmvMatrix); simpleShaderMatrixUniformDirty = false; } + + if (simpleShaderDepthUniformDirty) { + shaderManager->simpleProgram()->setUniformValue("depth", (GLfloat)q->state()->currentDepth); + simpleShaderDepthUniformDirty = false; + } } @@ -709,6 +714,7 @@ void QGL2PaintEngineExPrivate::fill(const QVectorPath& path) if (path.shape() == QVectorPath::RectangleHint) { QGLRect rect(points[0].x(), points[0].y(), points[2].x(), points[2].y()); prepareForDraw(currentBrush->isOpaque()); + composite(rect); } else if (path.shape() == QVectorPath::EllipseHint) { @@ -739,13 +745,13 @@ void QGL2PaintEngineExPrivate::fill(const QVectorPath& path) void QGL2PaintEngineExPrivate::fillStencilWithVertexArray(QGL2PEXVertexArray& vertexArray, bool useWindingFill) { // qDebug("QGL2PaintEngineExPrivate::fillStencilWithVertexArray()"); - if (stencilBuferDirty) { + if (stencilBufferDirty) { // Clear the stencil buffer to zeros glDisable(GL_STENCIL_TEST); glStencilMask(0xFFFF); // Enable writing to stencil buffer, otherwise glClear wont do anything. glClearStencil(0); // Clear to zero glClear(GL_STENCIL_BUFFER_BIT); - stencilBuferDirty = false; + stencilBufferDirty = false; } glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); // Disable color writes @@ -843,6 +849,7 @@ void QGL2PaintEngineExPrivate::prepareForDraw(bool srcPixelsAreOpaque) // The shader program has changed so mark all uniforms as dirty: brushUniformsDirty = true; shaderMatrixUniformDirty = true; + depthUniformDirty = true; } if (brushUniformsDirty && mode != ImageDrawingMode) @@ -853,6 +860,11 @@ void QGL2PaintEngineExPrivate::prepareForDraw(bool srcPixelsAreOpaque) shaderMatrixUniformDirty = false; } + if (depthUniformDirty) { + shaderManager->currentProgram()->setUniformValue("depth", (GLfloat)q->state()->currentDepth); + depthUniformDirty = false; + } + if (useGlobalOpacityUniform) shaderManager->currentProgram()->setUniformValue("globalOpacity", (GLfloat)q->state()->opacity); } @@ -1062,7 +1074,6 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(const QPointF &p, const QTextIte matrix.translate(p.x(), p.y()); ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions); - QFontEngineGlyphCache::Type glyphType = ti.fontEngine->glyphFormat >= 0 ? QFontEngineGlyphCache::Type(ti.fontEngine->glyphFormat) : QFontEngineGlyphCache::Raster_A8; @@ -1146,6 +1157,7 @@ bool QGL2PaintEngineEx::begin(QPaintDevice *pdev) } d->ctx->d_ptr->active_engine = this; + d->last_created_state = 0; d->drawable.makeCurrent(); QSize sz = d->drawable.size(); @@ -1172,12 +1184,16 @@ bool QGL2PaintEngineEx::begin(QPaintDevice *pdev) d->brushUniformsDirty = true; d->matrixDirty = true; d->compositionModeDirty = true; - d->stencilBuferDirty = true; + d->stencilBufferDirty = true; + d->simpleShaderDepthUniformDirty = true; + d->depthUniformDirty = true; d->use_system_clip = !systemClip().isEmpty(); glDisable(GL_DEPTH_TEST); glDisable(GL_SCISSOR_TEST); + glDepthFunc(GL_LEQUAL); + glDepthMask(false); QGLPixmapData *source = d->drawable.copyOnBegin(); if (d->drawable.context()->d_func()->clear_on_painter_begin && d->drawable.autoFillBackground()) { @@ -1201,7 +1217,7 @@ bool QGL2PaintEngineEx::begin(QPaintDevice *pdev) d->drawTexture(QRectF(rect), QRectF(rect), rect.size(), true); } - updateClipRegion(QRegion(), Qt::NoClip); + d->systemStateChanged(); return true; } @@ -1245,260 +1261,296 @@ void QGL2PaintEngineEx::ensureActive() ctx->d_ptr->active_engine = this; glDisable(GL_DEPTH_TEST); - glDisable(GL_SCISSOR_TEST); glViewport(0, 0, d->width, d->height); + setState(state()); - d->updateDepthClip(); } } +void QGL2PaintEngineExPrivate::updateDepthScissorTest() +{ + Q_Q(QGL2PaintEngineEx); + if (q->state()->depthTestEnabled) + glEnable(GL_DEPTH_TEST); + else + glDisable(GL_DEPTH_TEST); -/////////////////////////////////// State/Clipping stolen from QOpenGLPaintEngine ////////////////////////////////////////// + if (q->state()->scissorTestEnabled) + glEnable(GL_SCISSOR_TEST); + else + glDisable(GL_SCISSOR_TEST); +} void QGL2PaintEngineEx::clipEnabledChanged() { Q_D(QGL2PaintEngineEx); - d->updateDepthClip(); + d->simpleShaderDepthUniformDirty = true; + d->depthUniformDirty = true; + + if (painter()->hasClipping()) { + d->regenerateDepthClip(); + } else { + if (d->use_system_clip) { + state()->currentDepth = -0.5f; + } else { + glDisable(GL_DEPTH_TEST); + state()->depthTestEnabled = false; + } + } } -void QGL2PaintEngineEx::clip(const QVectorPath &path, Qt::ClipOperation op) +void QGL2PaintEngineExPrivate::writeClip(const QVectorPath &path, float depth) { -// qDebug("QGL2PaintEngineEx::clip()"); - const qreal *points = path.points(); - const QPainterPath::ElementType *types = path.elements(); - if (!types && path.shape() == QVectorPath::RectangleHint) { - QRectF r(points[0], points[1], points[4]-points[0], points[5]-points[1]); - updateClipRegion(QRegion(r.toRect()), op); - return; - } + transferMode(BrushDrawingMode); - QPainterPath p; - if (types) { - int id = 0; - for (int i=0; istate()->needsDepthBufferClear) { + glDepthMask(true); + glClearDepth(0.5); + glClear(GL_DEPTH_BUFFER_BIT); + q->state()->needsDepthBufferClear = false; + glDepthMask(false); } - if (path.hints() & QVectorPath::WindingFill) - p.setFillRule(Qt::WindingFill); - updateClipRegion(QRegion(p.toFillPolygon().toPolygon(), p.fillRule()), op); - return; + if (path.isEmpty()) + return; + + glDisable(GL_BLEND); + glDepthMask(false); + + vertexCoordinateArray.clear(); + vertexCoordinateArray.addPath(path, inverseScale); + + glDepthMask(GL_FALSE); + fillStencilWithVertexArray(vertexCoordinateArray, path.hasWindingFill()); + + // Stencil the clip onto the clip buffer + glColorMask(false, false, false, false); + glDepthMask(true); + + shaderManager->simpleProgram()->setUniformValue("depth", depth); + simpleShaderDepthUniformDirty = true; + + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_ALWAYS); + + glStencilFunc(GL_NOTEQUAL, 0, 0xFFFF); // Pass if stencil buff value != 0 + + glEnable(GL_STENCIL_TEST); + composite(vertexCoordinateArray.boundingRect()); + glDisable(GL_STENCIL_TEST); + + glColorMask(true, true, true, true); + glDepthMask(false); + + cleanStencilBuffer(vertexCoordinateArray.boundingRect()); } -void QGL2PaintEngineEx::updateClipRegion(const QRegion &clipRegion, Qt::ClipOperation op) +void QGL2PaintEngineEx::clip(const QVectorPath &path, Qt::ClipOperation op) { -// qDebug("QGL2PaintEngineEx::updateClipRegion()"); +// qDebug("QGL2PaintEngineEx::clip()"); Q_D(QGL2PaintEngineEx); - QRegion sysClip = systemClip(); - if (op == Qt::NoClip && !d->use_system_clip) { - state()->hasClipping = false; - state()->clipRegion = QRegion(); - d->updateDepthClip(); - return; - } + if (op == Qt::ReplaceClip && !d->hasClipOperations()) + op = Qt::IntersectClip; - bool isScreenClip = false; - if (!d->use_system_clip) { - QVector untransformedRects = clipRegion.rects(); + if (!path.isEmpty() && op == Qt::IntersectClip && (path.hints() & QVectorPath::RectangleHint)) { + const QPointF* const points = reinterpret_cast(path.points()); + QRectF rect(points[0], points[2]); - if (untransformedRects.size() == 1) { - QPainterPath path; - path.addRect(untransformedRects[0]); - //path = d->matrix.map(path); - path = state()->matrix.map(path); - -// if (path.contains(QRectF(QPointF(), d->drawable.size()))) -// isScreenClip = true; - if (path.contains(QRectF(0.0, 0.0, d->width, d->height))) - isScreenClip = true; + if (state()->matrix.type() <= QTransform::TxScale) { + rect = state()->matrix.mapRect(rect); + + if (d->use_system_clip && rect.contains(d->systemClip.boundingRect()) + || rect.contains(QRect(0, 0, d->width, d->height))) + return; } } -// QRegion region = isScreenClip ? QRegion() : clipRegion * d->matrix; - QRegion region = isScreenClip ? QRegion() : clipRegion * state()->matrix; switch (op) { case Qt::NoClip: - if (!d->use_system_clip) - break; - state()->clipRegion = sysClip; + if (d->use_system_clip) { + glEnable(GL_DEPTH_TEST); + state()->depthTestEnabled = true; + state()->currentDepth = -0.5; + } else { + glDisable(GL_DEPTH_TEST); + state()->depthTestEnabled = false; + } + state()->canRestoreClip = false; break; case Qt::IntersectClip: - if (isScreenClip) - return; - if (state()->hasClipping) { - state()->clipRegion &= region; - break; - } - // fall through + state()->maxDepth = (1.0f + state()->maxDepth) * 0.5; + d->writeClip(path, state()->maxDepth); + state()->currentDepth = 1.5 * state()->maxDepth - 0.5f; + state()->depthTestEnabled = true; + break; case Qt::ReplaceClip: - if (d->use_system_clip && !sysClip.isEmpty()) - state()->clipRegion = region & sysClip; - else - state()->clipRegion = region; + d->systemStateChanged(); + state()->maxDepth = 0.5f; + glDepthFunc(GL_ALWAYS); + d->writeClip(path, state()->maxDepth); + state()->currentDepth = 0.25f; + state()->canRestoreClip = false; + state()->depthTestEnabled = true; break; case Qt::UniteClip: - state()->clipRegion |= region; - if (d->use_system_clip && !sysClip.isEmpty()) - state()->clipRegion &= sysClip; - break; - default: + glDepthFunc(GL_ALWAYS); + d->writeClip(path, state()->maxDepth); + state()->canRestoreClip = false; + state()->depthTestEnabled = true; break; } - if (isScreenClip) { - state()->hasClipping = false; - state()->clipRegion = QRegion(); - } else { - state()->hasClipping = op != Qt::NoClip || d->use_system_clip; + glDepthFunc(GL_LEQUAL); + if (state()->depthTestEnabled) { + glEnable(GL_DEPTH_TEST); + d->simpleShaderDepthUniformDirty = true; + d->depthUniformDirty = true; } - - d->updateDepthClip(); } -void QGL2PaintEngineExPrivate::systemStateChanged() +void QGL2PaintEngineExPrivate::regenerateDepthClip() { - Q_Q(QGL2PaintEngineEx); - use_system_clip = !systemClip.isEmpty(); - - if (q->painter()->hasClipping()) - q->updateClipRegion(q->painter()->clipRegion(), Qt::ReplaceClip); - else - q->updateClipRegion(QRegion(), Qt::NoClip); + systemStateChanged(); + replayClipOperations(); } -void QGL2PaintEngineExPrivate::updateDepthClip() +void QGL2PaintEngineExPrivate::systemStateChanged() { -// qDebug("QGL2PaintEngineExPrivate::updateDepthClip()"); - Q_Q(QGL2PaintEngineEx); + use_system_clip = !systemClip.isEmpty(); - q->ensureActive(); glDisable(GL_DEPTH_TEST); + q->state()->depthTestEnabled = false; + q->state()->scissorTestEnabled = false; + q->state()->needsDepthBufferClear = true; + glDisable(GL_SCISSOR_TEST); - if (!q->state()->hasClipping) - return; + q->state()->currentDepth = -0.5f; + q->state()->maxDepth = 0.5f; - const QVector rects = q->state()->clipEnabled ? q->state()->clipRegion.rects() : q->systemClip().rects(); - if (rects.size() == 1) { - QRect fastClip = rects.at(0); + if (use_system_clip) { + QRect bounds = systemClip.boundingRect(); + if (systemClip.numRects() == 1 + && bounds == QRect(0, 0, width, height)) + { + q->state()->needsDepthBufferClear = true; + } else { + glEnable(GL_SCISSOR_TEST); - glEnable(GL_SCISSOR_TEST); + const int left = bounds.left(); + const int width = bounds.width(); + const int bottom = height - (bounds.top() + bounds.height()); + const int height = bounds.height(); - const int left = fastClip.left(); - const int width = fastClip.width(); - const int bottom = height - (fastClip.bottom() + 1); - const int height = fastClip.height(); + glScissor(left, bottom, width, height); - glScissor(left, bottom, width, height); - return; - } + QTransform transform = q->state()->matrix; + q->state()->matrix = QTransform(); + q->transformChanged(); - glClearDepth(0x0); - glDepthMask(true); - glClear(GL_DEPTH_BUFFER_BIT); - glClearDepth(0x1); + q->state()->needsDepthBufferClear = false; - glEnable(GL_SCISSOR_TEST); - for (int i = 0; i < rects.size(); ++i) { - QRect rect = rects.at(i); + glDepthMask(true); - const int left = rect.left(); - const int width = rect.width(); - const int bottom = height - (rect.bottom() + 1); - const int height = rect.height(); + glClearDepth(0); + glClear(GL_DEPTH_BUFFER_BIT); - glScissor(left, bottom, width, height); + QPainterPath path; + path.addRegion(systemClip); - glClear(GL_DEPTH_BUFFER_BIT); - } - glDisable(GL_SCISSOR_TEST); + glDepthFunc(GL_ALWAYS); + writeClip(qtVectorPathForPath(path), 0.0f); + glDepthFunc(GL_LEQUAL); - glDepthMask(false); - glDepthFunc(GL_LEQUAL); - glEnable(GL_DEPTH_TEST); -} + glEnable(GL_DEPTH_TEST); + q->state()->depthTestEnabled = true; + q->state()->scissorTestEnabled = true; + q->state()->matrix = transform; + q->transformChanged(); + } + q->state()->currentDepth = -0.5f; + simpleShaderDepthUniformDirty = true; + depthUniformDirty = true; + } +} void QGL2PaintEngineEx::setState(QPainterState *new_state) { -// qDebug("QGL2PaintEngineEx::setState()"); + // qDebug("QGL2PaintEngineEx::setState()"); Q_D(QGL2PaintEngineEx); QOpenGL2PaintEngineState *s = static_cast(new_state); - QOpenGL2PaintEngineState *old_state = state(); - const bool needsDepthClipUpdate = !old_state - || s->clipEnabled != old_state->clipEnabled - || (s->clipEnabled && s->clipRegion != old_state->clipRegion); QPaintEngineEx::setState(s); - if (needsDepthClipUpdate) - d->updateDepthClip(); + if (s == d->last_created_state) { + d->last_created_state = 0; + return; + } d->matrixDirty = true; d->compositionModeDirty = true; d->brushTextureDirty = true; d->brushUniformsDirty = true; + d->simpleShaderDepthUniformDirty = true; + d->depthUniformDirty = true; d->simpleShaderMatrixUniformDirty = true; d->shaderMatrixUniformDirty = true; + + if (old_state && old_state != s && old_state->canRestoreClip) { + d->updateDepthScissorTest(); + glDepthMask(false); + glDepthFunc(GL_LEQUAL); + s->maxDepth = old_state->maxDepth; + } else { + d->regenerateDepthClip(); + } } QPainterState *QGL2PaintEngineEx::createState(QPainterState *orig) const { + Q_D(const QGL2PaintEngineEx); + QOpenGL2PaintEngineState *s; if (!orig) s = new QOpenGL2PaintEngineState(); else s = new QOpenGL2PaintEngineState(*static_cast(orig)); + d->last_created_state = s; return s; } QOpenGL2PaintEngineState::QOpenGL2PaintEngineState(QOpenGL2PaintEngineState &other) : QPainterState(other) { - clipRegion = other.clipRegion; - hasClipping = other.hasClipping; + needsDepthBufferClear = other.needsDepthBufferClear; + depthTestEnabled = other.depthTestEnabled; + scissorTestEnabled = other.scissorTestEnabled; + currentDepth = other.currentDepth; + maxDepth = other.maxDepth; + canRestoreClip = other.canRestoreClip; } QOpenGL2PaintEngineState::QOpenGL2PaintEngineState() { - hasClipping = false; + needsDepthBufferClear = true; + depthTestEnabled = false; + scissorTestEnabled = false; + currentDepth = -0.5f; + maxDepth = 0.5f; + canRestoreClip = true; } QOpenGL2PaintEngineState::~QOpenGL2PaintEngineState() diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h index 7213474..2cea8d6 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h @@ -77,8 +77,15 @@ public: QOpenGL2PaintEngineState(); ~QOpenGL2PaintEngineState(); - QRegion clipRegion; - bool hasClipping; + bool needsDepthBufferClear; + qreal depthBufferClearValue; + + bool depthTestEnabled; + bool scissorTestEnabled; + qreal currentDepth; + qreal maxDepth; + + bool canRestoreClip; }; @@ -116,7 +123,6 @@ public: Type type() const { return OpenGL; } - // State stuff is just for clipping and ripped off from QGLPaintEngine void setState(QPainterState *s); QPainterState *createState(QPainterState *orig) const; inline QOpenGL2PaintEngineState *state() { @@ -125,7 +131,6 @@ public: inline const QOpenGL2PaintEngineState *state() const { return static_cast(QPaintEngineEx::state()); } - void updateClipRegion(const QRegion &clipRegion, Qt::ClipOperation op); virtual void sync(); private: @@ -180,9 +185,10 @@ public: QGLDrawable drawable; int width, height; QGLContext *ctx; - EngineMode mode; + mutable QOpenGL2PaintEngineState *last_created_state; + // Dirty flags bool matrixDirty; // Implies matrix uniforms are also dirty bool compositionModeDirty; @@ -190,7 +196,9 @@ public: bool brushUniformsDirty; bool simpleShaderMatrixUniformDirty; bool shaderMatrixUniformDirty; - bool stencilBuferDirty; + bool stencilBufferDirty; + bool depthUniformDirty; + bool simpleShaderDepthUniformDirty; const QBrush* currentBrush; // May not be the state's brush! @@ -206,8 +214,9 @@ public: QGLEngineShaderManager* shaderManager; - // Clipping & state stuff stolen from QOpenGLPaintEngine: - void updateDepthClip(); + void writeClip(const QVectorPath &path, float depth); + void updateDepthScissorTest(); + void regenerateDepthClip(); void systemStateChanged(); uint use_system_clip : 1; }; -- cgit v0.12 From 73ea2f5766d2c0925af1bee7037610c2c75e89c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Tue, 9 Jun 2009 10:54:42 +0200 Subject: Resolved FBO extensions as well when resolving GL 2 extensions. The new GL 2 text drawing requries the FBO function pointers to be resolved. --- src/opengl/qglextensions.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/opengl/qglextensions.cpp b/src/opengl/qglextensions.cpp index 3c198fb..10ca613 100644 --- a/src/opengl/qglextensions.cpp +++ b/src/opengl/qglextensions.cpp @@ -337,6 +337,9 @@ bool qt_resolve_version_2_0_functions(QGLContext *ctx) if (!qt_resolve_version_1_3_functions(ctx)) gl2supported = false; + if (!qt_resolve_framebufferobject_extensions(ctx)) + gl2supported = false; + if (glStencilOpSeparate) return gl2supported; -- cgit v0.12 From 6495eb4953c5fca93d8cfe91c66b50ce82ce24cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Tue, 9 Jun 2009 13:02:47 +0200 Subject: Optimized stencil buffer clearing in GL 2 paint engine. Based on Zack's patch, 17e1bca1ce366395f8331e16aa96b7176ca1abac. Instead of manually clearing the stencil buffer after drawing we simply do the clearing and drawing in one go. Reviewed-by: Trond --- .../gl2paintengineex/qpaintengineex_opengl2.cpp | 50 ++++------------------ .../gl2paintengineex/qpaintengineex_opengl2_p.h | 1 - 2 files changed, 9 insertions(+), 42 deletions(-) diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index fae3045..bdea187 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -732,12 +732,14 @@ void QGL2PaintEngineExPrivate::fill(const QVectorPath& path) // Stencil the brush onto the dest buffer glStencilFunc(GL_NOTEQUAL, 0, 0xFFFF); // Pass if stencil buff value != 0 + glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); + glEnable(GL_STENCIL_TEST); prepareForDraw(currentBrush->isOpaque()); composite(vertexCoordinateArray.boundingRect()); glDisable(GL_STENCIL_TEST); - cleanStencilBuffer(vertexCoordinateArray.boundingRect()); + glStencilMask(0); } } @@ -745,17 +747,17 @@ void QGL2PaintEngineExPrivate::fill(const QVectorPath& path) void QGL2PaintEngineExPrivate::fillStencilWithVertexArray(QGL2PEXVertexArray& vertexArray, bool useWindingFill) { // qDebug("QGL2PaintEngineExPrivate::fillStencilWithVertexArray()"); + glStencilMask(0xFFFF); // Enable stencil writes + if (stencilBufferDirty) { // Clear the stencil buffer to zeros glDisable(GL_STENCIL_TEST); - glStencilMask(0xFFFF); // Enable writing to stencil buffer, otherwise glClear wont do anything. glClearStencil(0); // Clear to zero glClear(GL_STENCIL_BUFFER_BIT); stencilBufferDirty = false; } glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); // Disable color writes - glStencilMask(0xFFFF); // Enable stencil writes glStencilFunc(GL_ALWAYS, 0, 0xFFFF); // Always pass the stencil test // Setup the stencil op: @@ -765,7 +767,7 @@ void QGL2PaintEngineExPrivate::fillStencilWithVertexArray(QGL2PEXVertexArray& ve } else glStencilOp(GL_KEEP, GL_KEEP, GL_INVERT); // Simply invert the stencil bit - // No point in using a fancy gradiant shader for writing into the stencil buffer! + // No point in using a fancy gradient shader for writing into the stencil buffer! useSimpleShader(); glEnable(GL_STENCIL_TEST); // For some reason, this has to happen _after_ the simple shader is use()'d @@ -776,41 +778,6 @@ void QGL2PaintEngineExPrivate::fillStencilWithVertexArray(QGL2PEXVertexArray& ve // Enable color writes & disable stencil writes glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - glStencilMask(0); -} - -void QGL2PaintEngineExPrivate::cleanStencilBuffer(const QGLRect& area) -{ -// qDebug("QGL2PaintEngineExPrivate::cleanStencilBuffer()"); - useSimpleShader(); - - GLfloat rectVerts[] = { - area.left, area.top, - area.left, area.bottom, - area.right, area.bottom, - area.right, area.top - }; - - glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR); - glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, rectVerts); - - glEnable(GL_STENCIL_TEST); - glStencilFunc(GL_ALWAYS, 0, 0xFFFF); // Always pass the stencil test - - glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); // Disable color writes - glStencilMask(0xFFFF); // Enable writing to stencil buffer - glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO); // Write 0's to stencil buffer - - glDisable(GL_BLEND); - - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - - glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR); - - // Enable color writes & disable stencil writes - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - glStencilMask(0); - glDisable(GL_STENCIL_TEST); } void QGL2PaintEngineExPrivate::prepareForDraw(bool srcPixelsAreOpaque) @@ -1339,15 +1306,16 @@ void QGL2PaintEngineExPrivate::writeClip(const QVectorPath &path, float depth) glDepthFunc(GL_ALWAYS); glStencilFunc(GL_NOTEQUAL, 0, 0xFFFF); // Pass if stencil buff value != 0 + glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); glEnable(GL_STENCIL_TEST); composite(vertexCoordinateArray.boundingRect()); glDisable(GL_STENCIL_TEST); + glStencilMask(0); + glColorMask(true, true, true, true); glDepthMask(false); - - cleanStencilBuffer(vertexCoordinateArray.boundingRect()); } void QGL2PaintEngineEx::clip(const QVectorPath &path, Qt::ClipOperation op) diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h index 2cea8d6..db39ced 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h @@ -174,7 +174,6 @@ public: // ^ Composites the bounding rect onto dest buffer void fillStencilWithVertexArray(QGL2PEXVertexArray& vertexArray, bool useWindingFill); // ^ Calls drawVertexArrays to render into stencil buffer - void cleanStencilBuffer(const QGLRect& area); void prepareForDraw(bool srcPixelsAreOpaque); -- cgit v0.12 From 923cadc12b993a0b41200750f151d73662856482 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Tue, 9 Jun 2009 13:23:08 +0200 Subject: Prevented pixmap FBOs from growing too big. If we're painting to very wide and then very tall pixmaps we don't want the FBO to grow to max_width * max_height, instead we should recreate the FBO if it grows too large compared to what's being painted. Reviewed-by: Trond --- src/opengl/qpixmapdata_gl.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/opengl/qpixmapdata_gl.cpp b/src/opengl/qpixmapdata_gl.cpp index 8d94c8b..98c406b 100644 --- a/src/opengl/qpixmapdata_gl.cpp +++ b/src/opengl/qpixmapdata_gl.cpp @@ -389,6 +389,11 @@ QPaintEngine* QGLPixmapData::paintEngine() const sz.setWidth(qMax(m_width, qRound(sz.width() * 1.5))); if (sz.height() < m_height) sz.setHeight(qMax(m_height, qRound(sz.height() * 1.5))); + + // wasting too much space? + if (sz.width() * sz.height() > m_width * m_height * 2.5) + sz = QSize(m_width, m_height); + delete textureBufferStack.at(currentTextureBuffer).fbo; textureBufferStack[currentTextureBuffer] = createTextureBuffer(sz, textureBufferStack.at(currentTextureBuffer).engine); -- cgit v0.12 From 7cd3e8233090f2937e38aff846a30635bcd14eb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Tue, 9 Jun 2009 14:05:03 +0200 Subject: Removed background caching in embeddeddialogs demo. No point in caching a background that is already a pixmap. When maximizing the window this pixmap gets huge, and it doesn't help performance either. Reviewed-by: Trond --- demos/embeddeddialogs/main.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/demos/embeddeddialogs/main.cpp b/demos/embeddeddialogs/main.cpp index cfb31c4..c9b6ee1 100644 --- a/demos/embeddeddialogs/main.cpp +++ b/demos/embeddeddialogs/main.cpp @@ -76,7 +76,6 @@ int main(int argc, char *argv[]) view.scale(0.5, 0.5); view.setRenderHints(view.renderHints() | QPainter::Antialiasing | QPainter::SmoothPixmapTransform); view.setBackgroundBrush(QPixmap(":/No-Ones-Laughing-3.jpg")); - view.setCacheMode(QGraphicsView::CacheBackground); view.setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate); view.show(); view.setWindowTitle("Embedded Dialogs Demo"); -- cgit v0.12 From 5039d39f3af42d23bba1f1c0ae10365ebcd82b4a Mon Sep 17 00:00:00 2001 From: Thierry Bastian Date: Tue, 9 Jun 2009 12:17:03 +0200 Subject: small change to reduce static data size --- src/corelib/kernel/qvariant.cpp | 2 +- src/gui/text/qtexthtmlparser.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp index 2ff9818..e6f1c48 100644 --- a/src/corelib/kernel/qvariant.cpp +++ b/src/corelib/kernel/qvariant.cpp @@ -1823,7 +1823,7 @@ QVariant::Type QVariant::nameToType(const char *name) #ifndef QT_NO_DATASTREAM enum { MapFromThreeCount = 35 }; -static const uint map_from_three[MapFromThreeCount] = +static const ushort map_from_three[MapFromThreeCount] = { QVariant::Invalid, QVariant::Map, diff --git a/src/gui/text/qtexthtmlparser.cpp b/src/gui/text/qtexthtmlparser.cpp index ee743dc..76c59c3 100644 --- a/src/gui/text/qtexthtmlparser.cpp +++ b/src/gui/text/qtexthtmlparser.cpp @@ -343,7 +343,7 @@ static QChar resolveEntity(const QString &entity) return e->code; } -static const uint windowsLatin1ExtendedCharacters[0xA0 - 0x80] = { +static const ushort windowsLatin1ExtendedCharacters[0xA0 - 0x80] = { 0x20ac, // 0x80 0x0081, // 0x81 direct mapping 0x201a, // 0x82 -- cgit v0.12 From b9f5e151b3c0bca74136720c5b42c9a93c8f25a8 Mon Sep 17 00:00:00 2001 From: Thierry Bastian Date: Tue, 9 Jun 2009 14:04:55 +0200 Subject: small improvement/refactor to cssparser --- src/gui/text/qcssparser.cpp | 42 +----------------------------- src/gui/text/qcssparser_p.h | 1 - tests/auto/qcssparser/tst_cssparser.cpp | 45 +++++++++++++++++++++++++++++++-- 3 files changed, 44 insertions(+), 44 deletions(-) diff --git a/src/gui/text/qcssparser.cpp b/src/gui/text/qcssparser.cpp index 0494b72..a05e5a1 100644 --- a/src/gui/text/qcssparser.cpp +++ b/src/gui/text/qcssparser.cpp @@ -57,46 +57,6 @@ QT_BEGIN_NAMESPACE using namespace QCss; -const char *Scanner::tokenName(QCss::TokenType t) -{ - switch (t) { - case NONE: return "NONE"; - case S: return "S"; - case CDO: return "CDO"; - case CDC: return "CDC"; - case INCLUDES: return "INCLUDES"; - case DASHMATCH: return "DASHMATCH"; - case LBRACE: return "LBRACE"; - case PLUS: return "PLUS"; - case GREATER: return "GREATER"; - case COMMA: return "COMMA"; - case STRING: return "STRING"; - case INVALID: return "INVALID"; - case IDENT: return "IDENT"; - case HASH: return "HASH"; - case ATKEYWORD_SYM: return "ATKEYWORD_SYM"; - case EXCLAMATION_SYM: return "EXCLAMATION_SYM"; - case LENGTH: return "LENGTH"; - case PERCENTAGE: return "PERCENTAGE"; - case NUMBER: return "NUMBER"; - case FUNCTION: return "FUNCTION"; - case COLON: return "COLON"; - case SEMICOLON: return "SEMICOLON"; - case RBRACE: return "RBRACE"; - case SLASH: return "SLASH"; - case MINUS: return "MINUS"; - case DOT: return "DOT"; - case STAR: return "STAR"; - case LBRACKET: return "LBRACKET"; - case RBRACKET: return "RBRACKET"; - case EQUAL: return "EQUAL"; - case LPAREN: return "LPAREN"; - case RPAREN: return "RPAREN"; - case OR: return "OR"; - } - return ""; -} - struct QCssKnownValue { const char *name; @@ -279,7 +239,7 @@ static const QCssKnownValue values[NumKnownValues - 1] = { }; //Map id to strings as they appears in the 'values' array above -static const int indexOfId[NumKnownValues] = { 0, 40, 47, 41, 48, 53, 34, 26, 68, 69, 25, 42, 5, 62, 46, +static const short indexOfId[NumKnownValues] = { 0, 40, 47, 41, 48, 53, 34, 26, 68, 69, 25, 42, 5, 62, 46, 29, 57, 58, 27, 50, 60, 6, 10, 38, 55, 19, 13, 17, 18, 20, 21, 49, 24, 45, 65, 36, 3, 2, 39, 61, 16, 11, 56, 14, 32, 63, 54, 64, 33, 67, 8, 28, 37, 12, 35, 59, 7, 9, 4, 66, 52, 22, 23, 30, 31, 1, 15, 0, 51, 44, 43 }; diff --git a/src/gui/text/qcssparser_p.h b/src/gui/text/qcssparser_p.h index 72bd637..81f306d 100644 --- a/src/gui/text/qcssparser_p.h +++ b/src/gui/text/qcssparser_p.h @@ -731,7 +731,6 @@ class Q_AUTOTEST_EXPORT Scanner public: static QString preprocess(const QString &input, bool *hasEscapeSequences = 0); static void scan(const QString &preprocessedInput, QVector *symbols); - static const char *tokenName(TokenType t); }; class Q_GUI_EXPORT Parser diff --git a/tests/auto/qcssparser/tst_cssparser.cpp b/tests/auto/qcssparser/tst_cssparser.cpp index b41a745..27258b7 100644 --- a/tests/auto/qcssparser/tst_cssparser.cpp +++ b/tests/auto/qcssparser/tst_cssparser.cpp @@ -114,11 +114,52 @@ void tst_CssParser::scanner_data() } } + +static char *tokenName(QCss::TokenType t) +{ + switch (t) { + case QCss::NONE: return "NONE"; + case QCss::S: return "S"; + case QCss::CDO: return "CDO"; + case QCss::CDC: return "CDC"; + case QCss::INCLUDES: return "INCLUDES"; + case QCss::DASHMATCH: return "DASHMATCH"; + case QCss::LBRACE: return "LBRACE"; + case QCss::PLUS: return "PLUS"; + case QCss::GREATER: return "GREATER"; + case QCss::COMMA: return "COMMA"; + case QCss::STRING: return "STRING"; + case QCss::INVALID: return "INVALID"; + case QCss::IDENT: return "IDENT"; + case QCss::HASH: return "HASH"; + case QCss::ATKEYWORD_SYM: return "ATKEYWORD_SYM"; + case QCss::EXCLAMATION_SYM: return "EXCLAMATION_SYM"; + case QCss::LENGTH: return "LENGTH"; + case QCss::PERCENTAGE: return "PERCENTAGE"; + case QCss::NUMBER: return "NUMBER"; + case QCss::FUNCTION: return "FUNCTION"; + case QCss::COLON: return "COLON"; + case QCss::SEMICOLON: return "SEMICOLON"; + case QCss::RBRACE: return "RBRACE"; + case QCss::SLASH: return "SLASH"; + case QCss::MINUS: return "MINUS"; + case QCss::DOT: return "DOT"; + case QCss::STAR: return "STAR"; + case QCss::LBRACKET: return "LBRACKET"; + case QCss::RBRACKET: return "RBRACKET"; + case QCss::EQUAL: return "EQUAL"; + case QCss::LPAREN: return "LPAREN"; + case QCss::RPAREN: return "RPAREN"; + case QCss::OR: return "OR"; + } + return ""; +} + static void debug(const QVector &symbols, int index = -1) { qDebug() << "all symbols:"; for (int i = 0; i < symbols.count(); ++i) - qDebug() << "(" << i << "); Token:" << QCss::Scanner::tokenName(symbols.at(i).token) << "; Lexem:" << symbols.at(i).lexem(); + qDebug() << "(" << i << "); Token:" << tokenName(symbols.at(i).token) << "; Lexem:" << symbols.at(i).lexem(); if (index != -1) qDebug() << "failure at index" << index; } @@ -160,7 +201,7 @@ void tst_CssParser::scanner() QCOMPARE(l.count(), 2); const QString expectedToken = l.at(0); const QString expectedLexem = l.at(1); - QString actualToken = QString::fromLatin1(QCss::Scanner::tokenName(symbols.at(i).token)); + QString actualToken = QString::fromLatin1(tokenName(symbols.at(i).token)); if (actualToken != expectedToken) { debug(symbols, i); QCOMPARE(actualToken, expectedToken); -- cgit v0.12 From d367ee08d1a07f1a30665b77ec11acec96e65a65 Mon Sep 17 00:00:00 2001 From: David Boddie Date: Tue, 9 Jun 2009 15:23:59 +0200 Subject: Doc: Fixed QWebPage::forwardUnsupportedContent documentation and added more information about Web plugins. Reviewed-by: Trust Me --- src/3rdparty/webkit/WebKit/qt/Api/qwebpage.cpp | 8 +++++--- src/3rdparty/webkit/WebKit/qt/Api/qwebsettings.cpp | 22 +++++++++++++++------- src/3rdparty/webkit/WebKit/qt/docs/qtwebkit.qdoc | 3 ++- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/src/3rdparty/webkit/WebKit/qt/Api/qwebpage.cpp b/src/3rdparty/webkit/WebKit/qt/Api/qwebpage.cpp index 01b68eb..77add54 100644 --- a/src/3rdparty/webkit/WebKit/qt/Api/qwebpage.cpp +++ b/src/3rdparty/webkit/WebKit/qt/Api/qwebpage.cpp @@ -1986,10 +1986,12 @@ bool QWebPage::isContentEditable() const /*! \property QWebPage::forwardUnsupportedContent - \brief whether QWebPage should forward unsupported content through the - unsupportedContent signal + \brief whether QWebPage should forward unsupported content - If disabled the download of such content is aborted immediately. + If enabled, the unsupportedContent() signal is emitted with a network reply that + can be used to read the content. + + If disabled, the download of such content is aborted immediately. By default unsupported content is not forwarded. */ diff --git a/src/3rdparty/webkit/WebKit/qt/Api/qwebsettings.cpp b/src/3rdparty/webkit/WebKit/qt/Api/qwebsettings.cpp index 1ad23f6..b516263 100644 --- a/src/3rdparty/webkit/WebKit/qt/Api/qwebsettings.cpp +++ b/src/3rdparty/webkit/WebKit/qt/Api/qwebsettings.cpp @@ -213,17 +213,25 @@ QWebSettings *QWebSettings::globalSettings() Each QWebPage object has its own QWebSettings object, which configures the settings for that page. If a setting is not configured, then it is looked up in the global settings object, which can be accessed using - QWebSettings::globalSettings(). + globalSettings(). - QWebSettings allows configuring font properties such as font size and font - family, the location of a custom stylesheet, and generic attributes like java - script, plugins, etc. The \l{QWebSettings::WebAttribute}{WebAttribute} - enum further describes this. + QWebSettings allows configuration of browser properties, such as font sizes and + families, the location of a custom style sheet, and generic attributes like + JavaScript and plugins. Individual attributes are set using the setAttribute() + function. The \l{QWebSettings::WebAttribute}{WebAttribute} enum further describes + each attribute. - QWebSettings also configures global properties such as the web page memory - cache and the web page icon database, local database storage and offline + QWebSettings also configures global properties such as the Web page memory + cache and the Web page icon database, local database storage and offline applications storage. + \section1 Enabling Plugins + + Support for browser plugins can enabled by setting the + \l{QWebSettings::PluginsEnabled}{PluginsEnabled} attribute. For many applications, + this attribute is enabled for all pages by setting it on the + \l{globalSettings()}{global settings object}. + \section1 Web Application Support WebKit provides support for features specified in \l{HTML 5} that improve the diff --git a/src/3rdparty/webkit/WebKit/qt/docs/qtwebkit.qdoc b/src/3rdparty/webkit/WebKit/qt/docs/qtwebkit.qdoc index 06305e0..119c126 100644 --- a/src/3rdparty/webkit/WebKit/qt/docs/qtwebkit.qdoc +++ b/src/3rdparty/webkit/WebKit/qt/docs/qtwebkit.qdoc @@ -96,7 +96,8 @@ Since WebKit supports the Netscape Plugin API, Qt applications can display Web pages that embed common plugins, as long as the user has the appropriate - binary files for those plugins installed. + binary files for those plugins installed and the \l{QWebSettings::PluginsEnabled} + attribute is set for the application. The following locations are searched for plugins: -- cgit v0.12 From 4d7a1cbb060a7fe933f674e1a9ebaa9e81fe2896 Mon Sep 17 00:00:00 2001 From: Martin Smith Date: Tue, 9 Jun 2009 15:54:19 +0200 Subject: qdoc: The gray version. --- src/corelib/kernel/qtimer.cpp | 2 +- tools/qdoc3/htmlgenerator.cpp | 2 -- tools/qdoc3/test/classic.css | 49 +++++++++++++++++++++++++++++++++++++------ 3 files changed, 44 insertions(+), 9 deletions(-) diff --git a/src/corelib/kernel/qtimer.cpp b/src/corelib/kernel/qtimer.cpp index 8ca53b9..29bdf7e 100644 --- a/src/corelib/kernel/qtimer.cpp +++ b/src/corelib/kernel/qtimer.cpp @@ -251,7 +251,7 @@ void QTimer::stop() /*! - \reimp + \reimp */ void QTimer::timerEvent(QTimerEvent *e) { diff --git a/tools/qdoc3/htmlgenerator.cpp b/tools/qdoc3/htmlgenerator.cpp index 0c21534..fb33de4 100644 --- a/tools/qdoc3/htmlgenerator.cpp +++ b/tools/qdoc3/htmlgenerator.cpp @@ -2349,8 +2349,6 @@ QString HtmlGenerator::highlightedCode(const QString& markedCode, // replace all <@link> tags: "(<@link node=\"([^\"]+)\">).*()" static const QString linkTag("link"); - if (src.contains("setAcceptDrops")) - qDebug() << "SRC:" << src; bool done = false; for (int i = 0, n = src.size(); i < n;) { if (src.at(i) == charLangle && src.at(i + 1).unicode() == '@') { diff --git a/tools/qdoc3/test/classic.css b/tools/qdoc3/test/classic.css index 85bb348..9c59c81 100644 --- a/tools/qdoc3/test/classic.css +++ b/tools/qdoc3/test/classic.css @@ -14,12 +14,49 @@ H3 { h3.fn,span.fn { - background-color: #e0eff6; + background-color: #eee; border-width: 1px; border-style: solid; - border-color: #3388be #3388be #e9f8ff #3388be; + border-color: #ddd #ddd #ddd #ddd ; font-weight: bold; padding: 6px 0px 6px 10px; + margin: 42px 0px 0px 0px; +} + +hr { + border: 0; + color: #9E9E9E; + background-color: #ccc; + height: 1px; + width: 100%; + text-align: left; + margin: 34px 0px 34px 0px; +} + +table { + border-width: 1px 1px 1px 1px; + border-style: solid; + border-color: #dddddd; + border-collapse: collapse; + background-color: #f0f0f0; + margin-left: 1.5%; + width: 97% +} + +table th { + border-width: 1px 1px 1px 2px; + padding: 4px; + border-style: solid; + border-color: #444; + color:white; + background-color:#444; +} + +p { + margin-left: 1.5%; + margin-top: 8px; + width: 97% + margin-bottom: 8px; } a:link @@ -66,7 +103,7 @@ body table td.memItemLeft { width: 200px; - padding: 1px 0px 0px 8px; + padding: 2px 0px 0px 8px; margin: 4px; border-top-width: 1px; border-right-width: 1px; @@ -76,7 +113,7 @@ table td.memItemLeft { border-right-color: #E0E0E0; border-bottom-color: #E0E0E0; border-left-color: #E0E0E0; - border-top-style: solid; + border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; @@ -85,7 +122,7 @@ table td.memItemLeft { white-space: nowrap } table td.memItemRight { - padding: 1px 8px 0px 8px; + padding: 2px 8px 0px 8px; margin: 4px; border-top-width: 1px; border-right-width: 1px; @@ -95,7 +132,7 @@ table td.memItemRight { border-right-color: #E0E0E0; border-bottom-color: #E0E0E0; border-left-color: #E0E0E0; - border-top-style: solid; + border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; -- cgit v0.12 From 6185ff436816738e933e3c88d44c45faa7f401f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Nilsen?= Date: Tue, 9 Jun 2009 16:13:18 +0200 Subject: Remove duplicated code for removing an item from the scene. Before we had almost two identical functions for removing an item from the scene. There was only minor differences depending on whether the item was removed from QGraphicsScene::removeItem or from the item's destructor. Now we have one function that handles both cases just fine. Reviewed-by: Andreas --- src/gui/graphicsview/qgraphicsitem.cpp | 36 +++--- src/gui/graphicsview/qgraphicsitem_p.h | 6 +- src/gui/graphicsview/qgraphicsscene.cpp | 193 +++++++++++++------------------- src/gui/graphicsview/qgraphicsscene.h | 1 - src/gui/graphicsview/qgraphicsscene_p.h | 5 +- 5 files changed, 101 insertions(+), 140 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index 5ba87ee..db16213 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -840,11 +840,11 @@ QVariant QGraphicsItemPrivate::inputMethodQueryHelper(Qt::InputMethodQuery query /*! \internal - If \a deleting is true, then this item is being deleted, and \a parent is - null. Make sure not to trigger any pure virtual function calls (e.g., - prepareGeometryChange). + Make sure not to trigger any pure virtual function calls (e.g., + prepareGeometryChange) if the item is in its destructor, i.e. + inDestructor is 1. */ -void QGraphicsItemPrivate::setParentItemHelper(QGraphicsItem *newParent, bool deleting) +void QGraphicsItemPrivate::setParentItemHelper(QGraphicsItem *newParent) { Q_Q(QGraphicsItem); if (newParent == q) { @@ -871,7 +871,7 @@ void QGraphicsItemPrivate::setParentItemHelper(QGraphicsItem *newParent, bool de // We anticipate geometry changes. If the item is deleted, it will be // removed from the index at a later stage, and the whole scene will be // updated. - if (!deleting) + if (!inDestructor) q_ptr->prepareGeometryChange(); const QVariant thisPointerVariant(qVariantFromValue(q)); @@ -883,7 +883,7 @@ void QGraphicsItemPrivate::setParentItemHelper(QGraphicsItem *newParent, bool de // Update toplevelitem list. If this item is being deleted, its parent // will be 0 but we don't want to register/unregister it in the TLI list. - if (scene && !deleting) { + if (scene && !inDestructor) { if (parent && !newParent) { scene->d_func()->registerTopLevelItem(q); } else if (!parent && newParent) { @@ -931,7 +931,7 @@ void QGraphicsItemPrivate::setParentItemHelper(QGraphicsItem *newParent, bool de updateAncestorFlag(QGraphicsItem::ItemClipsChildrenToShape); updateAncestorFlag(QGraphicsItem::ItemIgnoresTransformations); - if (!deleting) { + if (!inDestructor) { // Update item visible / enabled. if (!visible && !explicitlyHidden) setVisibleHelper(true, /* explicit = */ false); @@ -1115,22 +1115,22 @@ QGraphicsItem::QGraphicsItem(QGraphicsItemPrivate &dd, QGraphicsItem *parent, */ QGraphicsItem::~QGraphicsItem() { - if (d_ptr->scene && !d_ptr->parent) - d_ptr->scene->d_func()->unregisterTopLevelItem(this); + d_ptr->inDestructor = 1; + d_ptr->removeExtraItemCache(); clearFocus(); + if (!d_ptr->children.isEmpty()) { + QList oldChildren = d_ptr->children; + qDeleteAll(oldChildren); + Q_ASSERT(d_ptr->children.isEmpty()); + } - d_ptr->removeExtraItemCache(); - QList oldChildren = d_ptr->children; - qDeleteAll(oldChildren); - Q_ASSERT(d_ptr->children.isEmpty()); - - d_ptr->setParentItemHelper(0, /* deleting = */ true); if (d_ptr->scene) - d_ptr->scene->d_func()->_q_removeItemLater(this); + d_ptr->scene->d_func()->removeItemHelper(this); + else + d_ptr->setParentItemHelper(0); delete d_ptr->transformData; - delete d_ptr; qt_dataStore()->data.remove(this); @@ -1272,7 +1272,7 @@ QGraphicsWidget *QGraphicsItem::window() const */ void QGraphicsItem::setParentItem(QGraphicsItem *parent) { - d_ptr->setParentItemHelper(parent, /* deleting = */ false); + d_ptr->setParentItemHelper(parent); } /*! diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index e2a37a1..c502655 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -148,6 +148,7 @@ public: paintedViewBoundingRectsNeedRepaint(0), dirtySceneTransform(1), geometryChanged(0), + inDestructor(0), globalStackingOrder(-1), q_ptr(0) { @@ -183,7 +184,7 @@ public: void resolveDepth(int parentDepth); void addChild(QGraphicsItem *child); void removeChild(QGraphicsItem *child); - void setParentItemHelper(QGraphicsItem *parent, bool deleting); + void setParentItemHelper(QGraphicsItem *parent); void childrenBoundingRectHelper(QTransform *x, QRectF *rect); void initStyleOption(QStyleOptionGraphicsItem *option, const QTransform &worldTransform, const QRegion &exposedRegion, bool allItems = false) const; @@ -403,7 +404,8 @@ public: quint32 paintedViewBoundingRectsNeedRepaint : 1; quint32 dirtySceneTransform : 1; quint32 geometryChanged : 1; - quint32 unused : 16; // feel free to use + quint32 inDestructor : 1; + quint32 unused : 15; // feel free to use // Optional stacking order int globalStackingOrder; diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index e43c9cd..b63efd6 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -710,39 +710,65 @@ void QGraphicsScenePrivate::_q_processDirtyItems() \internal Schedules an item for removal. This function leaves some stale indexes - around in the BSP tree; these will be cleaned up the next time someone - triggers purgeRemovedItems(). + around in the BSP tree if called from the item's destructor; these will + be cleaned up the next time someone triggers purgeRemovedItems(). - Note: This function is called from QGraphicsItem's destructor. \a item is + Note: This function might get called from QGraphicsItem's destructor. \a item is being destroyed, so we cannot call any pure virtual functions on it (such as boundingRect()). Also, it is unnecessary to update the item's own state in any way. - - ### Refactoring: This function shares much functionality with removeItem() */ -void QGraphicsScenePrivate::_q_removeItemLater(QGraphicsItem *item) +void QGraphicsScenePrivate::removeItemHelper(QGraphicsItem *item) { Q_Q(QGraphicsScene); - // Clear focus on the item to remove any reference in the focusWidget - // chain. + // Clear focus on the item to remove any reference in the focusWidget chain. item->clearFocus(); - - int index = item->d_func()->index; - if (index != -1) { - // Important: The index is useless until purgeRemovedItems() is - // called. - indexedItems[index] = (QGraphicsItem *)0; - if (!purgePending) { + markDirty(item, QRectF(), false, false, false, false, /*removingItemFromScene=*/true); + + if (!item->d_ptr->inDestructor) { + // Can potentially call item->boundingRect() (virtual function), that's why + // we only can call this function if the item is not in its destructor. + removeFromIndex(item); + } else if (item->d_ptr->index != -1) { + // Important: The index is useless until purgeRemovedItems() is called. + indexedItems[item->d_ptr->index] = (QGraphicsItem *)0; + if (!purgePending) purgePending = true; - q->update(); - } removedItems << item; } else { // Recently added items are purged immediately. unindexedItems() never // contains stale items. unindexedItems.removeAll(item); - q->update(); + } + + if (!item->d_ptr->inDestructor && item == tabFocusFirst) { + QGraphicsWidget *widget = static_cast(item); + widget->d_func()->fixFocusChainBeforeReparenting(0, 0); + } + + item->d_func()->scene = 0; + + // Remove from parent, or unregister from toplevels. + if (QGraphicsItem *parentItem = item->parentItem()) { + if (parentItem->scene()) { + Q_ASSERT_X(parentItem->scene() == q, "QGraphicsScene::removeItem", + "Parent item's scene is different from this item's scene"); + item->d_ptr->setParentItemHelper(0); + } + } else { + unregisterTopLevelItem(item); + } + + if (!item->d_ptr->inDestructor) { + // Remove from our item lists. + int index = item->d_func()->index; + if (index != -1) { + freeItemIndexes << index; + indexedItems[index] = 0; + } else { + unindexedItems.removeAll(item); + } } // Reset the mouse grabber and focus item data. @@ -776,13 +802,19 @@ void QGraphicsScenePrivate::_q_removeItemLater(QGraphicsItem *item) ++iterator; } - // Reset the mouse grabber + if (!item->d_ptr->inDestructor) { + // Remove all children recursively + for (int i = 0; i < item->d_ptr->children.size(); ++i) + q->removeItem(item->d_ptr->children.at(i)); + } + + // Reset the mouse grabber and focus item data. if (mouseGrabberItems.contains(item)) - ungrabMouse(item, /* item is dying */ true); + ungrabMouse(item, /* item is dying */ item->d_ptr->inDestructor); // Reset the keyboard grabber if (keyboardGrabberItems.contains(item)) - ungrabKeyboard(item, /* item is dying */ true); + ungrabKeyboard(item, /* item is dying */ item->d_ptr->inDestructor); // Reset the last mouse grabber item if (item == lastMouseGrabberItem) @@ -801,8 +833,6 @@ void QGraphicsScenePrivate::_q_removeItemLater(QGraphicsItem *item) */ void QGraphicsScenePrivate::purgeRemovedItems() { - Q_Q(QGraphicsScene); - if (!purgePending && removedItems.isEmpty()) return; @@ -818,9 +848,6 @@ void QGraphicsScenePrivate::purgeRemovedItems() freeItemIndexes << i; } purgePending = false; - - // No locality info for the items; update the whole scene. - q->update(); } /*! @@ -3352,95 +3379,7 @@ void QGraphicsScene::removeItem(QGraphicsItem *item) return; } - // If the item has focus, remove it (and any focusWidget reference). - item->clearFocus(); - - // Clear its background - item->update(); - - // Note: This will access item's sceneBoundingRect(), which (as this is - // C++) is why we cannot call removeItem() from QGraphicsItem's - // destructor. - d->removeFromIndex(item); - - if (item == d->tabFocusFirst) { - QGraphicsWidget *widget = static_cast(item); - widget->d_func()->fixFocusChainBeforeReparenting(0, 0); - } - // Set the item's scene ptr to 0. - item->d_func()->scene = 0; - - // Remove from parent, or unregister from toplevels. - if (QGraphicsItem *parentItem = item->parentItem()) { - if (parentItem->scene()) { - Q_ASSERT_X(parentItem->scene() == this, "QGraphicsScene::removeItem", - "Parent item's scene is different from this item's scene"); - item->setParentItem(0); - } - } else { - d->unregisterTopLevelItem(item); - } - - // Remove from our item lists. - int index = item->d_func()->index; - if (index != -1) { - d->freeItemIndexes << index; - d->indexedItems[index] = 0; - } else { - d->unindexedItems.removeAll(item); - } - - if (item == d->focusItem) - d->focusItem = 0; - if (item == d->lastFocusItem) - d->lastFocusItem = 0; - if (item == d->activeWindow) { - // ### deactivate... - d->activeWindow = 0; - } - - // Disable selectionChanged() for individual items - ++d->selectionChanging; - int oldSelectedItemsSize = d->selectedItems.size(); - - // Update selected & hovered item bookkeeping - d->selectedItems.remove(item); - d->hoverItems.removeAll(item); - d->pendingUpdateItems.removeAll(item); - d->cachedItemsUnderMouse.removeAll(item); - d->unpolishedItems.removeAll(item); - d->resetDirtyItem(item); - - //We remove all references of item from the sceneEventFilter arrays - QMultiMap::iterator iterator = d->sceneEventFilters.begin(); - while (iterator != d->sceneEventFilters.end()) { - if (iterator.value() == item || iterator.key() == item) - iterator = d->sceneEventFilters.erase(iterator); - else - ++iterator; - } - - // Remove all children recursively - foreach (QGraphicsItem *child, item->children()) - removeItem(child); - - // Reset the mouse grabber and focus item data. - if (d->mouseGrabberItems.contains(item)) - d->ungrabMouse(item); - - // Reset the keyboard grabber - if (d->keyboardGrabberItems.contains(item)) - item->ungrabKeyboard(); - - // Reset the last mouse grabber item - if (item == d->lastMouseGrabberItem) - d->lastMouseGrabberItem = 0; - - // Reenable selectionChanged() for individual items - --d->selectionChanging; - - if (!d->selectionChanging && d->selectedItems.size() != oldSelectedItemsSize) - emit selectionChanged(); + d->removeItemHelper(item); // Deliver post-change notification item->itemChange(QGraphicsItem::ItemSceneHasChanged, newSceneVariant); @@ -5272,7 +5211,8 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * } void QGraphicsScenePrivate::markDirty(QGraphicsItem *item, const QRectF &rect, bool invalidateChildren, - bool maybeDirtyClipPath, bool force, bool ignoreOpacity) + bool maybeDirtyClipPath, bool force, bool ignoreOpacity, + bool removingItemFromScene) { Q_ASSERT(item); if (updateAll) @@ -5280,7 +5220,8 @@ void QGraphicsScenePrivate::markDirty(QGraphicsItem *item, const QRectF &rect, b if (item->d_ptr->discardUpdateRequest(/*ignoreClipping=*/maybeDirtyClipPath, /*ignoreVisibleBit=*/force, - /*ignoreDirtyBit=*/false, ignoreOpacity)) { + /*ignoreDirtyBit=*/removingItemFromScene, + /*ignoreOpacity=*/ignoreOpacity)) { return; } @@ -5293,6 +5234,24 @@ void QGraphicsScenePrivate::markDirty(QGraphicsItem *item, const QRectF &rect, b processDirtyItemsEmitted = true; } + if (removingItemFromScene) { + // Note that this function can be called from the item's destructor, so + // do NOT call any virtual functions on it within this block. + if ((connectedSignals & changedSignalMask) || views.isEmpty()) { + // This block of code is kept for compatibility. Since 4.5, by default + // QGraphicsView does not connect the signal and we use the below + // method of delivering updates. + q_func()->update(); + return; + } + + for (int i = 0; i < views.size(); ++i) { + QGraphicsViewPrivate *viewPrivate = views.at(i)->d_func(); + viewPrivate->updateRect(item->d_ptr->paintedViewBoundingRects.value(viewPrivate->viewport)); + } + return; + } + item->d_ptr->dirty = 1; if (fullItemUpdate) item->d_ptr->fullUpdatePending = 1; diff --git a/src/gui/graphicsview/qgraphicsscene.h b/src/gui/graphicsview/qgraphicsscene.h index 4c0f2ec..c4c9f9c 100644 --- a/src/gui/graphicsview/qgraphicsscene.h +++ b/src/gui/graphicsview/qgraphicsscene.h @@ -275,7 +275,6 @@ private: Q_DISABLE_COPY(QGraphicsScene) Q_PRIVATE_SLOT(d_func(), void _q_updateIndex()) Q_PRIVATE_SLOT(d_func(), void _q_emitUpdated()) - Q_PRIVATE_SLOT(d_func(), void _q_removeItemLater(QGraphicsItem *item)) Q_PRIVATE_SLOT(d_func(), void _q_updateLater()) Q_PRIVATE_SLOT(d_func(), void _q_polishItems()) Q_PRIVATE_SLOT(d_func(), void _q_updateSortCache()) diff --git a/src/gui/graphicsview/qgraphicsscene_p.h b/src/gui/graphicsview/qgraphicsscene_p.h index 42c4d8c..11e9b64 100644 --- a/src/gui/graphicsview/qgraphicsscene_p.h +++ b/src/gui/graphicsview/qgraphicsscene_p.h @@ -131,7 +131,7 @@ public: bool regenerateIndex; bool purgePending; - void _q_removeItemLater(QGraphicsItem *item); + void removeItemHelper(QGraphicsItem *item); QSet removedItems; void purgeRemovedItems(); @@ -264,7 +264,8 @@ public: QRegion *exposedRegion, QWidget *widget, QList *topLevelItems = 0, qreal parentOpacity = qreal(1.0)); void markDirty(QGraphicsItem *item, const QRectF &rect = QRectF(), bool invalidateChildren = false, - bool maybeDirtyClipPath = false, bool force = false, bool ignoreOpacity = false); + bool maybeDirtyClipPath = false, bool force = false, bool ignoreOpacity = false, + bool removingItemFromScene = false); void processDirtyItemsRecursive(QGraphicsItem *item, bool dirtyAncestorContainsChildren = false); inline void resetDirtyItem(QGraphicsItem *item) -- cgit v0.12 From a15cce3256e57464720ea7fe7cf663c973f43c7b Mon Sep 17 00:00:00 2001 From: Thierry Bastian Date: Tue, 9 Jun 2009 16:46:18 +0200 Subject: small changes in private headers --- src/gui/image/qpicture_p.h | 2 +- src/gui/painting/qtextureglyphcache_p.h | 2 +- src/gui/text/qfontengine.cpp | 6 ------ src/gui/text/qfontengine_p.h | 1 - src/gui/text/qfontengineglyphcache_p.h | 4 ++-- 5 files changed, 4 insertions(+), 11 deletions(-) diff --git a/src/gui/image/qpicture_p.h b/src/gui/image/qpicture_p.h index a3fd34f..3e8391f 100644 --- a/src/gui/image/qpicture_p.h +++ b/src/gui/image/qpicture_p.h @@ -69,7 +69,7 @@ class QPaintEngine; extern const char *qt_mfhdr_tag; -class Q_GUI_EXPORT QPicturePrivate +class QPicturePrivate { Q_DECLARE_PUBLIC(QPicture) friend class QPicturePaintEngine; diff --git a/src/gui/painting/qtextureglyphcache_p.h b/src/gui/painting/qtextureglyphcache_p.h index cb5be75..689c091 100644 --- a/src/gui/painting/qtextureglyphcache_p.h +++ b/src/gui/painting/qtextureglyphcache_p.h @@ -121,7 +121,7 @@ protected: }; -class Q_GUI_EXPORT QImageTextureGlyphCache : public QTextureGlyphCache +class QImageTextureGlyphCache : public QTextureGlyphCache { public: QImageTextureGlyphCache(QFontEngineGlyphCache::Type type, const QTransform &matrix) diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp index 6e8adcf..79e341a 100644 --- a/src/gui/text/qfontengine.cpp +++ b/src/gui/text/qfontengine.cpp @@ -70,12 +70,6 @@ static inline bool qtransform_equals_no_translate(const QTransform &a, const QTr } } - - -QFontEngineGlyphCache::~QFontEngineGlyphCache() -{ -} - // Harfbuzz helper functions static HB_Bool hb_stringToGlyphs(HB_Font font, const HB_UChar16 *string, hb_uint32 length, HB_Glyph *glyphs, hb_uint32 *numGlyphs, HB_Bool rightToLeft) diff --git a/src/gui/text/qfontengine_p.h b/src/gui/text/qfontengine_p.h index 0f8d81c..3ef9d5f 100644 --- a/src/gui/text/qfontengine_p.h +++ b/src/gui/text/qfontengine_p.h @@ -93,7 +93,6 @@ struct QGlyphLayout; class Q_GUI_EXPORT QFontEngine : public QObject { - Q_OBJECT public: enum Type { Box, diff --git a/src/gui/text/qfontengineglyphcache_p.h b/src/gui/text/qfontengineglyphcache_p.h index 8589cc6..ca67e3f 100644 --- a/src/gui/text/qfontengineglyphcache_p.h +++ b/src/gui/text/qfontengineglyphcache_p.h @@ -72,7 +72,7 @@ QT_BEGIN_NAMESPACE -class Q_GUI_EXPORT QFontEngineGlyphCache +class QFontEngineGlyphCache { public: QFontEngineGlyphCache(const QTransform &matrix) : m_transform(matrix) { } @@ -83,7 +83,7 @@ public: Raster_Mono }; - virtual ~QFontEngineGlyphCache(); + virtual ~QFontEngineGlyphCache() { } QTransform m_transform; }; -- cgit v0.12 From df7d44d9e826e608d280270125b2d376c33c66ad Mon Sep 17 00:00:00 2001 From: Thierry Bastian Date: Tue, 9 Jun 2009 17:02:32 +0200 Subject: removed foreach usage from animation API --- src/corelib/animation/qparallelanimationgroup.cpp | 33 +++++++++++++---------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/src/corelib/animation/qparallelanimationgroup.cpp b/src/corelib/animation/qparallelanimationgroup.cpp index c148cb5d..6ec4679 100644 --- a/src/corelib/animation/qparallelanimationgroup.cpp +++ b/src/corelib/animation/qparallelanimationgroup.cpp @@ -135,13 +135,14 @@ void QParallelAnimationGroup::updateCurrentTime(int) // simulate completion of the loop int dura = duration(); if (dura > 0) { - foreach (QAbstractAnimation *animation, d->animations) { - animation->setCurrentTime(dura); // will stop + for (int i = 0; i < d->animations.size(); ++i) { + d->animations.at(i)->setCurrentTime(dura); // will stop } } } else if (d->currentLoop < d->lastLoop) { // simulate completion of the loop seeking backwards - foreach (QAbstractAnimation *animation, d->animations) { + for (int i = 0; i < d->animations.size(); ++i) { + QAbstractAnimation *animation = d->animations.at(i); animation->setCurrentTime(0); animation->stop(); } @@ -154,7 +155,8 @@ void QParallelAnimationGroup::updateCurrentTime(int) __LINE__, d->currentTime, d->currentLoop, d->lastLoop, timeFwd, d->lastCurrentTime, state()); #endif // finally move into the actual time of the current loop - foreach (QAbstractAnimation *animation, d->animations) { + for (int i = 0; i < d->animations.size(); ++i) { + QAbstractAnimation *animation = d->animations.at(i); const int dura = animation->totalDuration(); if (dura == -1 && d->isUncontrolledAnimationFinished(animation)) continue; @@ -200,17 +202,18 @@ void QParallelAnimationGroup::updateState(QAbstractAnimation::State oldState, switch (newState) { case Stopped: - foreach (QAbstractAnimation *animation, d->animations) - animation->stop(); + for (int i = 0; i < d->animations.size(); ++i) + d->animations.at(i)->stop(); d->disconnectUncontrolledAnimations(); break; case Paused: - foreach (QAbstractAnimation *animation, d->animations) - animation->pause(); + for (int i = 0; i < d->animations.size(); ++i) + d->animations.at(i)->pause(); break; case Running: d->connectUncontrolledAnimations(); - foreach (QAbstractAnimation *animation, d->animations) { + for (int i = 0; i < d->animations.size(); ++i) { + QAbstractAnimation *animation = d->animations.at(i); animation->stop(); animation->setDirection(d->direction); animation->start(); @@ -243,8 +246,8 @@ void QParallelAnimationGroupPrivate::_q_uncontrolledAnimationFinished() return; int maxDuration = 0; - foreach (QAbstractAnimation *a, animations) - maxDuration = qMax(maxDuration, a->totalDuration()); + for (int i = 0; i < animations.size(); ++i) + maxDuration = qMax(maxDuration, animations.at(i)->totalDuration()); if (currentTime >= maxDuration) q->stop(); @@ -267,7 +270,8 @@ void QParallelAnimationGroupPrivate::connectUncontrolledAnimations() { Q_Q(QParallelAnimationGroup); - foreach (QAbstractAnimation *animation, animations) { + for (int i = 0; i < animations.size(); ++i) { + QAbstractAnimation *animation = animations.at(i); if (animation->duration() == -1 || animation->loopCount() < 0) { uncontrolledFinishTime[animation] = -1; QObject::connect(animation, SIGNAL(finished()), q, SLOT(_q_uncontrolledAnimationFinished())); @@ -288,8 +292,9 @@ void QParallelAnimationGroup::updateDirection(QAbstractAnimation::Direction dire Q_D(QParallelAnimationGroup); //we need to update the direction of the current animation if (state() != Stopped) { - foreach(QAbstractAnimation *anim, d->animations) { - anim->setDirection(direction); + for (int i = 0; i < d->animations.size(); ++i) { + QAbstractAnimation *animation = d->animations.at(i); + animation->setDirection(direction); } } else { if (direction == Forward) { -- cgit v0.12 From 861bf225fedc452ab5b18c12e18e38c4172a5f1a Mon Sep 17 00:00:00 2001 From: Thierry Bastian Date: Tue, 9 Jun 2009 17:04:33 +0200 Subject: Improves the documentation of QHeaderView::setResizeMode to specify that the section indicated by the parameter logicalIndex should exist Task-number: 255541 --- src/gui/itemviews/qheaderview.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/gui/itemviews/qheaderview.cpp b/src/gui/itemviews/qheaderview.cpp index d28c08a..7ad825a 100644 --- a/src/gui/itemviews/qheaderview.cpp +++ b/src/gui/itemviews/qheaderview.cpp @@ -1153,7 +1153,8 @@ void QHeaderView::setResizeMode(ResizeMode mode) \overload Sets the constraints on how the section specified by \a logicalIndex in - the header can be resized to those described by the given \a mode. + the header can be resized to those described by the given \a mode. The logical + index should exist at the time this function is called. \note This setting will be ignored for the last section if the stretchLastSection property is set to true. This is the default for the horizontal headers provided -- cgit v0.12 From 2312b121131774a84d01854b3e47d3d2a035a6a1 Mon Sep 17 00:00:00 2001 From: Denis Dzyubenko Date: Thu, 4 Jun 2009 12:10:06 +0200 Subject: Implemented the NET_WM_SYNC protocol on X11. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Done with Thorbjørn Lindeijer Task-number: 220550 Reviewed-by: Thorbjørn Lindeijer Reviewed-by: mae --- src/gui/kernel/qapplication_x11.cpp | 87 ++++++++++++++++++++++++++++++++++++- src/gui/kernel/qt_x11_p.h | 6 +++ src/gui/kernel/qwidget_p.h | 8 ++++ src/gui/kernel/qwidget_x11.cpp | 28 +++++++++++- 4 files changed, 127 insertions(+), 2 deletions(-) diff --git a/src/gui/kernel/qapplication_x11.cpp b/src/gui/kernel/qapplication_x11.cpp index 1473421..8ebea19 100644 --- a/src/gui/kernel/qapplication_x11.cpp +++ b/src/gui/kernel/qapplication_x11.cpp @@ -157,6 +157,8 @@ static const char * x11_atomnames = { "WM_TAKE_FOCUS\0" "_NET_WM_PING\0" "_NET_WM_CONTEXT_HELP\0" + "_NET_WM_SYNC_REQUEST\0" + "_NET_WM_SYNC_REQUEST_COUNTER\0" // ICCCM window state "WM_STATE\0" @@ -508,6 +510,7 @@ static Bool qt_xfixes_scanner(Display*, XEvent *event, XPointer arg) class QETWidget : public QWidget // event translator widget { public: + QWidgetPrivate* d_func() { return QWidget::d_func(); } bool translateMouseEvent(const XEvent *); void translatePaintEvent(const XEvent *); bool translateConfigEvent(const XEvent *); @@ -718,6 +721,44 @@ static int qt_xio_errhandler(Display *) } #endif +#ifndef QT_NO_XSYNC +struct qt_sync_request_event_data +{ + WId window; +}; + +#if defined(Q_C_CALLBACKS) +extern "C" { +#endif + +static Bool qt_sync_request_scanner(Display*, XEvent *event, XPointer arg) +{ + qt_sync_request_event_data *data = + reinterpret_cast(arg); + if (event->type == ClientMessage && + event->xany.window == data->window && + event->xclient.message_type == ATOM(WM_PROTOCOLS) && + (Atom)event->xclient.data.l[0] == ATOM(_NET_WM_SYNC_REQUEST)) { + QWidget *w = QWidget::find(event->xany.window); + if (QTLWExtra *tlw = ((QETWidget*)w)->d_func()->maybeTopData()) { + const ulong timestamp = (const ulong) event->xclient.data.l[1]; + if (timestamp > X11->time) + X11->time = timestamp; + if (timestamp == CurrentTime || timestamp > tlw->syncRequestTimestamp) { + tlw->syncRequestTimestamp = timestamp; + tlw->newCounterValueLo = event->xclient.data.l[2]; + tlw->newCounterValueHi = event->xclient.data.l[3]; + } + } + return true; + } + return false; +} + +#if defined(Q_C_CALLBACKS) +} +#endif +#endif // QT_NO_XSYNC static void qt_x11_create_intern_atoms() { @@ -2090,6 +2131,13 @@ void qt_init(QApplicationPrivate *priv, int, #endif // QT_RUNTIME_XCURSOR #endif // QT_NO_XCURSOR +#ifndef QT_NO_XSYNC + int xsync_evbase, xsync_errbase; + int major, minor; + if (XSyncQueryExtension(X11->display, &xsync_evbase, &xsync_errbase)) + XSyncInitialize(X11->display, &major, &minor); +#endif // QT_NO_XSYNC + #ifndef QT_NO_XINERAMA #ifdef QT_RUNTIME_XINERAMA X11->ptrXineramaQueryExtension = 0; @@ -3116,6 +3164,19 @@ int QApplication::x11ClientMessage(QWidget* w, XEvent* event, bool passive_only) XSendEvent(event->xclient.display, event->xclient.window, False, SubstructureNotifyMask|SubstructureRedirectMask, event); } +#ifndef QT_NO_XSYNC + } else if (a == ATOM(_NET_WM_SYNC_REQUEST)) { + const ulong timestamp = (const ulong) event->xclient.data.l[1]; + if (timestamp > X11->time) + X11->time = timestamp; + if (QTLWExtra *tlw = w->d_func()->maybeTopData()) { + if (timestamp == CurrentTime || timestamp > tlw->syncRequestTimestamp) { + tlw->syncRequestTimestamp = timestamp; + tlw->newCounterValueLo = event->xclient.data.l[2]; + tlw->newCounterValueHi = event->xclient.data.l[3]; + } + } +#endif } } else if (event->xclient.message_type == ATOM(_QT_SCROLL_DONE)) { widget->translateScrollDoneEvent(event); @@ -4144,7 +4205,9 @@ bool QETWidget::translateMouseEvent(const XEvent *event) || ((nextEvent.type == EnterNotify || nextEvent.type == LeaveNotify) && qt_button_down == this) || (nextEvent.type == ClientMessage - && nextEvent.xclient.message_type == ATOM(_QT_SCROLL_DONE))) { + && (nextEvent.xclient.message_type == ATOM(_QT_SCROLL_DONE) || + (nextEvent.xclient.message_type == ATOM(WM_PROTOCOLS) && + (Atom)nextEvent.xclient.data.l[0] == ATOM(_NET_WM_SYNC_REQUEST))))) { qApp->x11ProcessEvent(&nextEvent); continue; } else if (nextEvent.type != MotionNotify || @@ -5200,6 +5263,14 @@ bool QETWidget::translateConfigEvent(const XEvent *event) otherEvent.xconfigure.border_width; } } +#ifndef QT_NO_XSYNC + qt_sync_request_event_data sync_event; + sync_event.window = internalWinId(); + for (XEvent ev;;) { + if (!XCheckIfEvent(X11->display, &ev, &qt_sync_request_scanner, (XPointer)&sync_event)) + break; + } +#endif // QT_NO_XSYNC } QRect cr (geometry()); @@ -5285,6 +5356,20 @@ bool QETWidget::translateConfigEvent(const XEvent *event) if (d->extra && d->extra->topextra) d->extra->topextra->inTopLevelResize = false; } +#ifndef QT_NO_XSYNC + if (QTLWExtra *tlwExtra = d->maybeTopData()) { + if (tlwExtra->newCounterValueLo != 0 || tlwExtra->newCounterValueHi != 0) { + XSyncValue value; + XSyncIntsToValue(&value, + tlwExtra->newCounterValueLo, + tlwExtra->newCounterValueHi); + + XSyncSetCounter(X11->display, tlwExtra->syncUpdateCounter, value); + tlwExtra->newCounterValueHi = 0; + tlwExtra->newCounterValueLo = 0; + } + } +#endif return true; } diff --git a/src/gui/kernel/qt_x11_p.h b/src/gui/kernel/qt_x11_p.h index b9ace9d..21bb550 100644 --- a/src/gui/kernel/qt_x11_p.h +++ b/src/gui/kernel/qt_x11_p.h @@ -154,6 +154,10 @@ extern "C" { # include #endif // QT_NO_XRENDER +#ifndef QT_NO_XSYNC +# include "X11/extensions/sync.h" +#endif + // #define QT_NO_XKB #ifndef QT_NO_XKB # include @@ -514,6 +518,8 @@ struct QX11Data WM_TAKE_FOCUS, _NET_WM_PING, _NET_WM_CONTEXT_HELP, + _NET_WM_SYNC_REQUEST, + _NET_WM_SYNC_REQUEST_COUNTER, // ICCCM window state WM_STATE, diff --git a/src/gui/kernel/qwidget_p.h b/src/gui/kernel/qwidget_p.h index bf4f091..ff194f7 100644 --- a/src/gui/kernel/qwidget_p.h +++ b/src/gui/kernel/qwidget_p.h @@ -131,6 +131,10 @@ struct QTLWExtra { uint embedded : 1; // *************************** Platform specific values (bit fields first) ********** +#ifndef QT_NO_XSYNC + int newCounterValueHi : 32; + uint newCounterValueLo : 32; +#endif #if defined(Q_WS_X11) // <----------------------------------------------------------- X11 uint spont_unmapped: 1; // window was spontaneously unmapped uint dnd : 1; // DND properties installed @@ -156,6 +160,10 @@ struct QTLWExtra { QWSManager *qwsManager; #endif #endif +#ifndef QT_NO_XSYNC + WId syncUpdateCounter; + ulong syncRequestTimestamp; +#endif }; struct QWExtra { diff --git a/src/gui/kernel/qwidget_x11.cpp b/src/gui/kernel/qwidget_x11.cpp index 4e34045..8159f8e 100644 --- a/src/gui/kernel/qwidget_x11.cpp +++ b/src/gui/kernel/qwidget_x11.cpp @@ -754,11 +754,14 @@ void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyO qBound(1, data.crect.width(), XCOORD_MAX), qBound(1, data.crect.height(), XCOORD_MAX)); XStoreName(dpy, id, appName.data()); - Atom protocols[4]; + Atom protocols[5]; int n = 0; protocols[n++] = ATOM(WM_DELETE_WINDOW); // support del window protocol protocols[n++] = ATOM(WM_TAKE_FOCUS); // support take focus window protocol protocols[n++] = ATOM(_NET_WM_PING); // support _NET_WM_PING protocol +#ifndef QT_NO_XSYNC + protocols[n++] = ATOM(_NET_WM_SYNC_REQUEST); // support _NET_WM_SYNC_REQUEST protocol +#endif // QT_NO_XSYNC if (flags & Qt::WindowContextHelpButtonHint) protocols[n++] = ATOM(_NET_WM_CONTEXT_HELP); XSetWMProtocols(dpy, id, protocols, n); @@ -1877,6 +1880,23 @@ void QWidgetPrivate::show_sys() if (setUserTime) qt_net_update_user_time(q, userTime); +#ifndef QT_NO_XSYNC + if (!topData()->syncUpdateCounter) { + XSyncValue value; + XSyncIntToValue(&value, 0); + topData()->syncUpdateCounter = XSyncCreateCounter(X11->display, value); + + XChangeProperty(X11->display, q->internalWinId(), + ATOM(_NET_WM_SYNC_REQUEST_COUNTER), + XA_CARDINAL, + 32, PropModeReplace, + (uchar *) &topData()->syncUpdateCounter, 1); + + topData()->newCounterValueHi = 0; + topData()->newCounterValueLo = 0; + } +#endif + if (!topData()->embedded && (topData()->validWMState || topData()->waitingForMapNotify) && !q->isMinimized()) { @@ -2687,6 +2707,12 @@ void QWidgetPrivate::createTLSysExtra() extra->topextra->waitingForMapNotify = 0; extra->topextra->parentWinId = 0; extra->topextra->userTimeWindow = 0; +#ifndef QT_NO_XSYNC + extra->topextra->syncUpdateCounter = 0; + extra->topextra->syncRequestTimestamp = 0; + extra->topextra->newCounterValueHi = 0; + extra->topextra->newCounterValueLo = 0; +#endif } void QWidgetPrivate::deleteTLSysExtra() -- cgit v0.12 From 2dc47ad36f235ba053a329179be4ed87d0b4d484 Mon Sep 17 00:00:00 2001 From: Benjamin Poulain Date: Tue, 9 Jun 2009 18:48:16 +0200 Subject: Add support for TIFF formats (Mono and indexed) Add support for reading and writing for Mono, MonoLSB and Indexed images in the tiff format. Previously, the images were always written in RGB32, dismissing the input format. Task-number: 254317 Reviewed-by: Samuel --- src/plugins/imageformats/tiff/qtiffhandler.cpp | 342 +++++++++++++++++++------ tests/auto/qimagewriter/tst_qimagewriter.cpp | 26 ++ 2 files changed, 285 insertions(+), 83 deletions(-) diff --git a/src/plugins/imageformats/tiff/qtiffhandler.cpp b/src/plugins/imageformats/tiff/qtiffhandler.cpp index 77dfeb3..791aeaa 100644 --- a/src/plugins/imageformats/tiff/qtiffhandler.cpp +++ b/src/plugins/imageformats/tiff/qtiffhandler.cpp @@ -131,58 +131,138 @@ bool QTiffHandler::read(QImage *image) if (!canRead()) return false; - TIFF *tiff = TIFFClientOpen("foo", - "r", - this, - qtiffReadProc, - qtiffWriteProc, - qtiffSeekProc, - qtiffCloseProc, - qtiffSizeProc, - qtiffMapProc, - qtiffUnmapProc); - - if (tiff) { - uint32 width = 0; - uint32 height = 0; - TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &width); - TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &height); - if (image->size() != QSize(width, height) || image->format() != QImage::Format_ARGB32) - *image = QImage(width, height, QImage::Format_ARGB32); + TIFF *const tiff = TIFFClientOpen("foo", + "r", + this, + qtiffReadProc, + qtiffWriteProc, + qtiffSeekProc, + qtiffCloseProc, + qtiffSizeProc, + qtiffMapProc, + qtiffUnmapProc); + + if (!tiff) { + return false; + } + uint32 width; + uint32 height; + uint16 photometric; + if (!TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &width) + || !TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &height) + || !TIFFGetField(tiff, TIFFTAG_PHOTOMETRIC, &photometric)) { + TIFFClose(tiff); + return false; + } + + if (photometric == PHOTOMETRIC_MINISBLACK || photometric == PHOTOMETRIC_MINISWHITE) { + if (image->size() != QSize(width, height) || image->format() != QImage::Format_Mono) + *image = QImage(width, height, QImage::Format_Mono); + QVector colortable(2); + if (photometric == PHOTOMETRIC_MINISBLACK) { + colortable[0] = 0xff000000; + colortable[1] = 0xffffffff; + } else { + colortable[0] = 0xffffffff; + colortable[1] = 0xff000000; + } + image->setColorTable(colortable); + if (!image->isNull()) { - if (TIFFReadRGBAImageOriented(tiff, width, height, reinterpret_cast(image->bits()), ORIENTATION_TOPLEFT, 0)) { - uint16 resUnit = RESUNIT_NONE; - float resX = 0; - float resY = 0; - TIFFGetField(tiff, TIFFTAG_RESOLUTIONUNIT, &resUnit); - TIFFGetField(tiff, TIFFTAG_XRESOLUTION, &resX); - TIFFGetField(tiff, TIFFTAG_YRESOLUTION, &resY); - switch(resUnit) { - case RESUNIT_CENTIMETER: - image->setDotsPerMeterX(qRound(resX * 100)); - image->setDotsPerMeterY(qRound(resY * 100)); - break; - case RESUNIT_INCH: - image->setDotsPerMeterX(qRound(resX * (100 / 2.54))); - image->setDotsPerMeterY(qRound(resY * (100 / 2.54))); - break; - default: - // do nothing as defaults have already - // been set within the QImage class - break; + for (uint32 y=0; yscanLine(y), y, 0) < 0) { + TIFFClose(tiff); + return false; + } + } + } + } else { + uint16 bitPerSample; + if (!TIFFGetField(tiff, TIFFTAG_BITSPERSAMPLE, &bitPerSample)) { + TIFFClose(tiff); + return false; + } + if (photometric == PHOTOMETRIC_PALETTE && bitPerSample == 8) { + if (image->size() != QSize(width, height) || image->format() != QImage::Format_Indexed8) + *image = QImage(width, height, QImage::Format_Indexed8); + if (!image->isNull()) { + // create the color table + const uint16 tableSize = 256; + uint16 *redTable = static_cast(qMalloc(tableSize * sizeof(uint16))); + uint16 *greenTable = static_cast(qMalloc(tableSize * sizeof(uint16))); + uint16 *blueTable = static_cast(qMalloc(tableSize * sizeof(uint16))); + if (!redTable || !greenTable || !blueTable) { + TIFFClose(tiff); + return false; + } + if (!TIFFGetField(tiff, TIFFTAG_COLORMAP, &redTable, &greenTable, &blueTable)) { + TIFFClose(tiff); + return false; + } + + QVector qtColorTable(tableSize); + for (int i = 0; isetColorTable(qtColorTable); + for (uint32 y=0; yscanLine(y), y, 0) < 0) { + TIFFClose(tiff); + return false; + } + } + + // free redTable, greenTable and greenTable done by libtiff + } + } else { + if (image->size() != QSize(width, height) || image->format() != QImage::Format_ARGB32) + *image = QImage(width, height, QImage::Format_ARGB32); + if (!image->isNull()) { + if (TIFFReadRGBAImageOriented(tiff, width, height, reinterpret_cast(image->bits()), ORIENTATION_TOPLEFT, 0)) { + for (uint32 y=0; yscanLine(y), width); + } else { + TIFFClose(tiff); + return false; } - for (uint32 y=0; yscanLine(y), width); - } else { - *image = QImage(); } } - TIFFClose(tiff); } - if (image->isNull()) + if (image->isNull()) { + TIFFClose(tiff); return false; + } + + float resX = 0; + float resY = 0; + uint16 resUnit = RESUNIT_NONE; + if (TIFFGetField(tiff, TIFFTAG_RESOLUTIONUNIT, &resUnit) + && TIFFGetField(tiff, TIFFTAG_XRESOLUTION, &resX) + && TIFFGetField(tiff, TIFFTAG_YRESOLUTION, &resY)) { + + switch(resUnit) { + case RESUNIT_CENTIMETER: + image->setDotsPerMeterX(qRound(resX * 100)); + image->setDotsPerMeterY(qRound(resY * 100)); + break; + case RESUNIT_INCH: + image->setDotsPerMeterX(qRound(resX * (100 / 2.54))); + image->setDotsPerMeterY(qRound(resY * (100 / 2.54))); + break; + default: + // do nothing as defaults have already + // been set within the QImage class + break; + } + } + TIFFClose(tiff); return true; } @@ -191,48 +271,145 @@ bool QTiffHandler::write(const QImage &image) if (!device()->isWritable()) return false; - TIFF *tiff = TIFFClientOpen("foo", - "w", - this, - qtiffReadProc, - qtiffWriteProc, - qtiffSeekProc, - qtiffCloseProc, - qtiffSizeProc, - qtiffMapProc, - qtiffUnmapProc); - - if (tiff) { - int width = image.width(); - int height = image.height(); - int depth = 32; - - if (!TIFFSetField(tiff, TIFFTAG_IMAGEWIDTH, width) - || !TIFFSetField(tiff, TIFFTAG_IMAGELENGTH, height) - || !TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB) - || !TIFFSetField(tiff, TIFFTAG_COMPRESSION, compression == NoCompression ? COMPRESSION_NONE : COMPRESSION_LZW) - || !TIFFSetField(tiff, TIFFTAG_SAMPLESPERPIXEL, depth/8) - || !TIFFSetField(tiff, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG) - || !TIFFSetField(tiff, TIFFTAG_BITSPERSAMPLE, 8)) { + TIFF *const tiff = TIFFClientOpen("foo", + "w", + this, + qtiffReadProc, + qtiffWriteProc, + qtiffSeekProc, + qtiffCloseProc, + qtiffSizeProc, + qtiffMapProc, + qtiffUnmapProc); + if (!tiff) + return false; + + const int width = image.width(); + const int height = image.height(); + + if (!TIFFSetField(tiff, TIFFTAG_IMAGEWIDTH, width) + || !TIFFSetField(tiff, TIFFTAG_IMAGELENGTH, height) + || !TIFFSetField(tiff, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG)) { + TIFFClose(tiff); + return false; + } + + // set the resolution + bool resolutionSet = false; + const int dotPerMeterX = image.dotsPerMeterX(); + const int dotPerMeterY = image.dotsPerMeterY(); + if ((dotPerMeterX % 100) == 0 + && (dotPerMeterY % 100) == 0) { + resolutionSet = TIFFSetField(tiff, TIFFTAG_RESOLUTIONUNIT, RESUNIT_CENTIMETER) + && TIFFSetField(tiff, TIFFTAG_XRESOLUTION, dotPerMeterX/100.0) + && TIFFSetField(tiff, TIFFTAG_YRESOLUTION, dotPerMeterY/100.0); + } else { + resolutionSet = TIFFSetField(tiff, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH) + && TIFFSetField(tiff, TIFFTAG_XRESOLUTION, static_cast(image.logicalDpiX())) + && TIFFSetField(tiff, TIFFTAG_YRESOLUTION, static_cast(image.logicalDpiY())); + } + if (!resolutionSet) { + TIFFClose(tiff); + return false; + } + + // configure image depth + const QImage::Format format = image.format(); + if (format == QImage::Format_Mono || format == QImage::Format_MonoLSB) { + uint16 photometric = PHOTOMETRIC_MINISBLACK; + if (image.colorTable().at(0) == 0xffffffff) + photometric = PHOTOMETRIC_MINISWHITE; + if (!TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, photometric) + || !TIFFSetField(tiff, TIFFTAG_COMPRESSION, compression == NoCompression ? COMPRESSION_NONE : COMPRESSION_CCITTRLE)) { TIFFClose(tiff); return false; } - // set the resolution - bool resolutionSet = false; - const int dotPerMeterX = image.dotsPerMeterX(); - const int dotPerMeterY = image.dotsPerMeterY(); - if ((dotPerMeterX % 100) == 0 - && (dotPerMeterY % 100) == 0) { - resolutionSet = TIFFSetField(tiff, TIFFTAG_RESOLUTIONUNIT, RESUNIT_CENTIMETER) - && TIFFSetField(tiff, TIFFTAG_XRESOLUTION, dotPerMeterX/100.0) - && TIFFSetField(tiff, TIFFTAG_YRESOLUTION, dotPerMeterY/100.0); - } else { - resolutionSet = TIFFSetField(tiff, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH) - && TIFFSetField(tiff, TIFFTAG_XRESOLUTION, static_cast(image.logicalDpiX())) - && TIFFSetField(tiff, TIFFTAG_YRESOLUTION, static_cast(image.logicalDpiY())); + // try to do the conversion in chunks no greater than 16 MB + int chunks = (width * height / (1024 * 1024 * 16)) + 1; + int chunkHeight = qMax(height / chunks, 1); + + int y = 0; + while (y < height) { + QImage chunk = image.copy(0, y, width, qMin(chunkHeight, height - y)).convertToFormat(QImage::Format_Mono); + + int chunkStart = y; + int chunkEnd = y + chunk.height(); + while (y < chunkEnd) { + if (TIFFWriteScanline(tiff, reinterpret_cast(chunk.scanLine(y - chunkStart)), y) != 1) { + TIFFClose(tiff); + return false; + } + ++y; + } + } + TIFFClose(tiff); + } else if (format == QImage::Format_Indexed8) { + if (!TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_PALETTE) + || !TIFFSetField(tiff, TIFFTAG_COMPRESSION, compression == NoCompression ? COMPRESSION_NONE : COMPRESSION_PACKBITS) + || !TIFFSetField(tiff, TIFFTAG_BITSPERSAMPLE, 8)) { + TIFFClose(tiff); + return false; + } + //// write the color table + // allocate the color tables + uint16 *redTable = static_cast(qMalloc(256 * sizeof(uint16))); + uint16 *greenTable = static_cast(qMalloc(256 * sizeof(uint16))); + uint16 *blueTable = static_cast(qMalloc(256 * sizeof(uint16))); + if (!redTable || !greenTable || !blueTable) { + TIFFClose(tiff); + return false; + } + + // set the color table + const QVector colorTable = image.colorTable(); + + const int tableSize = colorTable.size(); + Q_ASSERT(tableSize <= 256); + for (int i = 0; i(chunk.scanLine(y - chunkStart)), y) != 1) { + TIFFClose(tiff); + return false; + } + ++y; + } } - if (!resolutionSet) { + TIFFClose(tiff); + + } else { + if (!TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB) + || !TIFFSetField(tiff, TIFFTAG_COMPRESSION, compression == NoCompression ? COMPRESSION_NONE : COMPRESSION_LZW) + || !TIFFSetField(tiff, TIFFTAG_SAMPLESPERPIXEL, 4) + || !TIFFSetField(tiff, TIFFTAG_BITSPERSAMPLE, 8)) { TIFFClose(tiff); return false; } @@ -260,9 +437,8 @@ bool QTiffHandler::write(const QImage &image) } } TIFFClose(tiff); - } else { - return false; } + return true; } diff --git a/tests/auto/qimagewriter/tst_qimagewriter.cpp b/tests/auto/qimagewriter/tst_qimagewriter.cpp index 349afa5..3ceb2c2 100644 --- a/tests/auto/qimagewriter/tst_qimagewriter.cpp +++ b/tests/auto/qimagewriter/tst_qimagewriter.cpp @@ -59,6 +59,7 @@ Q_DECLARE_METATYPE(QStringMap) Q_DECLARE_METATYPE(QIntList) Q_DECLARE_METATYPE(QImageWriter::ImageWriterError) Q_DECLARE_METATYPE(QIODevice *) +Q_DECLARE_METATYPE(QImage::Format) //TESTED_FILES= @@ -82,6 +83,9 @@ private slots: void writeImage2(); void supportedFormats(); + void readWriteNonDestructive_data(); + void readWriteNonDestructive(); + #if defined QTEST_HAVE_TIFF void largeTiff(); #endif @@ -376,6 +380,28 @@ void tst_QImageWriter::supportedFormats() QCOMPARE(formatSet.size(), formats.size()); } +void tst_QImageWriter::readWriteNonDestructive_data() +{ + QTest::addColumn("format"); + QTest::addColumn("expectedFormat"); + QTest::newRow("tiff mono") << QImage::Format_Mono << QImage::Format_Mono; + QTest::newRow("tiff indexed") << QImage::Format_Indexed8 << QImage::Format_Indexed8; + QTest::newRow("tiff rgb32") << QImage::Format_ARGB32 << QImage::Format_ARGB32; +} + +void tst_QImageWriter::readWriteNonDestructive() +{ + QFETCH(QImage::Format, format); + QFETCH(QImage::Format, expectedFormat); + QImage image = QImage(prefix + "colorful.bmp").convertToFormat(format); + QVERIFY(image.save(prefix + "gen-readWriteNonDestructive.tiff")); + + QImage image2 = QImage(prefix + "gen-readWriteNonDestructive.tiff"); + QImage::Format readFormat = image2.format(); + QCOMPARE(readFormat, expectedFormat); + QCOMPARE(image, image2); +} + void tst_QImageWriter::setDescription_data() { QTest::addColumn("fileName"); -- cgit v0.12 From 2af18f51f216d5c624ce28b3fa966a17050d882b Mon Sep 17 00:00:00 2001 From: Andreas Aardal Hanssen Date: Tue, 9 Jun 2009 17:45:04 +0200 Subject: Fix sorting bug when using BSP tree index + add autotest. We use stable sorting to keep insertion order. This works fine as long as we sort a complete list of siblings in one go, and this list already has items in insertion order. But if we shuffle such a list, the only way to get proper sort order again (with insertion order intact), is if each item has a sibling index. We used to have this, but we don't have it anymore (as it's not needed for NoIndex mode). So until we separate the BSP index into a separate class and add this index there, we add this workaround which uses the toplevelitems list to ensure the items have the correct order. Reviewed-by: bnilsen --- src/gui/graphicsview/qgraphicsitem.cpp | 8 +--- src/gui/graphicsview/qgraphicsscene.cpp | 46 +++++++++++++++------ tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp | 56 ++++++++++++++++++++++++++ 3 files changed, 92 insertions(+), 18 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index db16213..f50d210 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -6190,10 +6190,8 @@ void QGraphicsItem::addToIndex() // ### add to child index only if applicable return; } - if (d_ptr->scene) { + if (d_ptr->scene) d_ptr->scene->d_func()->addToIndex(this); - d_ptr->scene->d_func()->markDirty(this); - } } /*! @@ -6209,10 +6207,8 @@ void QGraphicsItem::removeFromIndex() // ### remove from child index only if applicable return; } - if (d_ptr->scene) { - d_ptr->scene->d_func()->markDirty(this); + if (d_ptr->scene) d_ptr->scene->d_func()->removeFromIndex(this); - } } /*! diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index b63efd6..e6c3503 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -5112,18 +5112,42 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * } else if (indexMethod == QGraphicsScene::NoIndex || !exposedRegion) { children = &this->topLevelItems; } else { - tmp = estimateItemsInRect(viewTransform.inverted().mapRect(exposedRegion->boundingRect())); + QRectF sceneRect = viewTransform.inverted().mapRect(QRectF(exposedRegion->boundingRect().adjusted(-1, -1, 1, 1))); + if (!largestUntransformableItem.isEmpty()) { + // ### Nuke this when we move the indexing code into a separate + // class. All the largestUntransformableItem code should then go + // away, and the estimate function should return untransformable + // items as well. + QRectF untr = largestUntransformableItem; + QRectF ltri = viewTransform.inverted().mapRect(untr); + ltri.adjust(-untr.width(), -untr.height(), untr.width(), untr.height()); + sceneRect.adjust(-ltri.width(), -ltri.height(), ltri.width(), ltri.height()); + } + tmp = estimateItemsInRect(sceneRect); QList tli; - for (int i = 0; i < tmp.size(); ++i) { - QGraphicsItem *it = tmp.at(i)->topLevelItem(); - if (!it->d_ptr->itemDiscovered) { - tli << it; - it->d_ptr->itemDiscovered = 1; + for (int i = 0; i < tmp.size(); ++i) + tmp.at(i)->topLevelItem()->d_ptr->itemDiscovered = 1; + + // Sort if the toplevel list is unsorted. + if (needSortTopLevelItems) { + needSortTopLevelItems = false; + qStableSort(this->topLevelItems.begin(), + this->topLevelItems.end(), qt_notclosestLeaf); + } + + for (int i = 0; i < this->topLevelItems.size(); ++i) { + // ### Investigate smarter ways. Looping through all top level + // items is not optimal. If the BSP tree is to have maximum + // effect, it should be possible to sort the subset of items + // quickly. We must use this approach for now, as it's the only + // current way to keep the stable sorting order (insertion order). + QGraphicsItem *item = this->topLevelItems.at(i); + if (item->d_ptr->itemDiscovered) { + item->d_ptr->itemDiscovered = 0; + tli << item; } } - for (int i = 0; i < tli.size(); ++i) - tli.at(i)->d_ptr->itemDiscovered = 0; tmp = tli; children = &tmp; @@ -5147,9 +5171,7 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * if (item && item->d_ptr->needSortChildren) { item->d_ptr->needSortChildren = 0; qStableSort(children->begin(), children->end(), qt_notclosestLeaf); - } else if (!item && children == &tmp) { - qStableSort(children->begin(), children->end(), qt_notclosestLeaf); - } else if (!item && needSortTopLevelItems) { + } else if (!item && needSortTopLevelItems && children != &tmp) { needSortTopLevelItems = false; qStableSort(children->begin(), children->end(), qt_notclosestLeaf); } @@ -5220,7 +5242,7 @@ void QGraphicsScenePrivate::markDirty(QGraphicsItem *item, const QRectF &rect, b if (item->d_ptr->discardUpdateRequest(/*ignoreClipping=*/maybeDirtyClipPath, /*ignoreVisibleBit=*/force, - /*ignoreDirtyBit=*/removingItemFromScene, + /*ignoreDirtyBit=*/removingItemFromScene || invalidateChildren, /*ignoreOpacity=*/ignoreOpacity)) { return; } diff --git a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp index af34fe5..481dc6b 100644 --- a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp +++ b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp @@ -226,6 +226,8 @@ private slots: void itemUsesExtendedStyleOption(); void itemSendsGeometryChanges(); void moveItem(); + void sorting_data(); + void sorting(); // task specific tests below me void task141694_textItemEnsureVisible(); @@ -6926,5 +6928,59 @@ void tst_QGraphicsItem::moveItem() QCOMPARE(view.paintedRegion, expectedParentRegion); } +void tst_QGraphicsItem::sorting_data() +{ + QTest::addColumn("index"); + + QTest::newRow("NoIndex") << int(QGraphicsScene::NoIndex); + QTest::newRow("BspTreeIndex") << int(QGraphicsScene::BspTreeIndex); +} + +void tst_QGraphicsItem::sorting() +{ + _paintedItems.clear(); + + QGraphicsScene scene; + QGraphicsItem *grid[100][100]; + for (int x = 0; x < 100; ++x) { + for (int y = 0; y < 100; ++y) { + PainterItem *item = new PainterItem; + item->setPos(x * 25, y * 25); + item->setData(0, QString("%1x%2").arg(x).arg(y)); + grid[x][y] = item; + scene.addItem(item); + } + } + + PainterItem *item1 = new PainterItem; + PainterItem *item2 = new PainterItem; + item1->setData(0, "item1"); + item2->setData(0, "item2"); + scene.addItem(item1); + scene.addItem(item2); + + QGraphicsView view(&scene); + view.setResizeAnchor(QGraphicsView::NoAnchor); + view.setTransformationAnchor(QGraphicsView::NoAnchor); + view.resize(100, 100); + view.setFrameStyle(0); + view.show(); +#ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(&view); +#endif + QTest::qWait(100); + + _paintedItems.clear(); + + view.viewport()->repaint(); + + QCOMPARE(_paintedItems, QList() + << grid[0][0] << grid[0][1] << grid[0][2] << grid[0][3] + << grid[1][0] << grid[1][1] << grid[1][2] << grid[1][3] + << grid[2][0] << grid[2][1] << grid[2][2] << grid[2][3] + << grid[3][0] << grid[3][1] << grid[3][2] << grid[3][3] + << item1 << item2); +} + QTEST_MAIN(tst_QGraphicsItem) #include "tst_qgraphicsitem.moc" -- cgit v0.12 From 5b24c5793607c809b1bac82c7cc3696001ee9217 Mon Sep 17 00:00:00 2001 From: Prasanth Ullattil Date: Tue, 9 Jun 2009 18:49:40 +0200 Subject: Opening links with cyrillic file names does not work in QLabel. QDestopServices was converting the file names to percentage encoding before calling ShellExecute. This will not work with URLs without a scheme. These are now being treated similar to a file. Task-number: 254501 Reviewed-by: Jens Bache-Wiig --- src/gui/util/qdesktopservices_win.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/gui/util/qdesktopservices_win.cpp b/src/gui/util/qdesktopservices_win.cpp index 9f8efb4..a8aa11c 100644 --- a/src/gui/util/qdesktopservices_win.cpp +++ b/src/gui/util/qdesktopservices_win.cpp @@ -165,6 +165,9 @@ static bool launchWebBrowser(const QUrl &url) if (!url.isValid()) return false; + if (url.scheme().isEmpty()) + return openDocument(url); + quintptr returnValue; returnValue = (quintptr)ShellExecute(0, 0, (TCHAR *) QString::fromUtf8(url.toEncoded().constData()).utf16(), 0, 0, SW_SHOWNORMAL); -- cgit v0.12 From 73fa8dd86f14ab161c84fa9224cd4335f352ba75 Mon Sep 17 00:00:00 2001 From: Jason McDonald Date: Wed, 10 Jun 2009 16:10:21 +1000 Subject: Fix license headers for QStringBuilder. Only release branches are allowed to have the Commercial usage header. All other branches must have the No Commercial Usage header. Reviewed-by: Trust Me --- src/corelib/tools/qstringbuilder.cpp | 12 ++++++------ src/corelib/tools/qstringbuilder.h | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/corelib/tools/qstringbuilder.cpp b/src/corelib/tools/qstringbuilder.cpp index 03d8160..740deb4 100644 --- a/src/corelib/tools/qstringbuilder.cpp +++ b/src/corelib/tools/qstringbuilder.cpp @@ -3,14 +3,14 @@ ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** Contact: Qt Software Information (qt-info@nokia.com) ** -** This file is part of the $MODULE$ of the Qt Toolkit. +** This file is part of the QtCore module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ -** Commercial Usage -** Licensees holding valid Qt Commercial licenses may use this file in -** accordance with the Qt Commercial License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Nokia. +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser diff --git a/src/corelib/tools/qstringbuilder.h b/src/corelib/tools/qstringbuilder.h index 2c31476..30a7c67 100644 --- a/src/corelib/tools/qstringbuilder.h +++ b/src/corelib/tools/qstringbuilder.h @@ -3,14 +3,14 @@ ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** Contact: Qt Software Information (qt-info@nokia.com) ** -** This file is part of the $MODULE$ of the Qt Toolkit. +** This file is part of the QtCore module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ -** Commercial Usage -** Licensees holding valid Qt Commercial licenses may use this file in -** accordance with the Qt Commercial License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Nokia. +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser -- cgit v0.12 From b2edf6ee037decf53c7d2698863ba63742317acc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Wed, 10 Jun 2009 10:21:19 +0200 Subject: Fixed clipping bug in raster paint engine causing rendering artifacts. The artifacts were visible in the mainwindow demo when dragging the top toolbar separator left and right. We need to check that rect clipping is actually activated before we compare the new clip rect with the old, otherwise the clip type and clip bound flags won't get updated. --- src/gui/painting/qpaintengine_raster.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index 0810bb9..7ed2dfd 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -4311,7 +4311,7 @@ QClipData::QClipData(int height) clipSpanHeight = height; m_clipLines = 0; - allocated = height; + allocated = 0; m_spans = 0; xmin = xmax = ymin = ymax = 0; count = 0; @@ -4479,7 +4479,7 @@ void QClipData::fixup() */ void QClipData::setClipRect(const QRect &rect) { - if (rect == clipRect) + if (hasRectClip && rect == clipRect) return; // qDebug() << "setClipRect" << clipSpanHeight << count << allocated << rect; -- cgit v0.12 From f0f12f3d1ad2041c57095edaa7683c5d3599a3e6 Mon Sep 17 00:00:00 2001 From: Jason McDonald Date: Wed, 10 Jun 2009 18:47:49 +1000 Subject: Fix some incorrect license headers. The MODULE placeholder shouldn't be used anymore, and neither should the old Trolltech license header. Reviewed-by: Trust Me --- doc/src/diagrams/programs/easingcurve/main.cpp | 36 +++++++++++++++++++++-- src/gui/math3d/qgenericmatrix.cpp | 2 +- src/gui/math3d/qgenericmatrix.h | 2 +- src/gui/math3d/qmatrix4x4.cpp | 2 +- src/gui/math3d/qmatrix4x4.h | 2 +- src/gui/math3d/qquaternion.cpp | 2 +- src/gui/math3d/qquaternion.h | 2 +- src/gui/math3d/qvector2d.cpp | 2 +- src/gui/math3d/qvector2d.h | 2 +- src/gui/math3d/qvector3d.cpp | 2 +- src/gui/math3d/qvector3d.h | 2 +- src/gui/math3d/qvector4d.cpp | 2 +- src/gui/math3d/qvector4d.h | 2 +- tests/auto/math3d/qmatrixnxn/tst_qmatrixnxn.cpp | 2 +- tests/auto/math3d/qquaternion/tst_qquaternion.cpp | 2 +- tests/auto/math3d/qvectornd/tst_qvectornd.cpp | 2 +- tests/auto/math3d/shared/math3dincludes.h | 2 +- 17 files changed, 49 insertions(+), 19 deletions(-) diff --git a/doc/src/diagrams/programs/easingcurve/main.cpp b/doc/src/diagrams/programs/easingcurve/main.cpp index 98e9d37..8d399a3 100644 --- a/doc/src/diagrams/programs/easingcurve/main.cpp +++ b/doc/src/diagrams/programs/easingcurve/main.cpp @@ -1,11 +1,41 @@ /**************************************************************************** ** -** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** Contact: Qt Software Information (qt-info@nokia.com) ** -** This file is part of the $MODULE$ of the Qt Toolkit. +** This file is part of the examples of the Qt Toolkit. ** -** $TROLLTECH_DUAL_LICENSE$ +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ ** ****************************************************************************/ diff --git a/src/gui/math3d/qgenericmatrix.cpp b/src/gui/math3d/qgenericmatrix.cpp index 6ecd878..19a0f6e 100644 --- a/src/gui/math3d/qgenericmatrix.cpp +++ b/src/gui/math3d/qgenericmatrix.cpp @@ -3,7 +3,7 @@ ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** Contact: Qt Software Information (qt-info@nokia.com) ** -** This file is part of the $MODULE$ of the Qt Toolkit. +** This file is part of the QtGui module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage diff --git a/src/gui/math3d/qgenericmatrix.h b/src/gui/math3d/qgenericmatrix.h index b4d3707..330ded2 100644 --- a/src/gui/math3d/qgenericmatrix.h +++ b/src/gui/math3d/qgenericmatrix.h @@ -3,7 +3,7 @@ ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** Contact: Qt Software Information (qt-info@nokia.com) ** -** This file is part of the $MODULE$ of the Qt Toolkit. +** This file is part of the QtGui module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage diff --git a/src/gui/math3d/qmatrix4x4.cpp b/src/gui/math3d/qmatrix4x4.cpp index 8ef4da3..a69b9df 100644 --- a/src/gui/math3d/qmatrix4x4.cpp +++ b/src/gui/math3d/qmatrix4x4.cpp @@ -3,7 +3,7 @@ ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** Contact: Qt Software Information (qt-info@nokia.com) ** -** This file is part of the $MODULE$ of the Qt Toolkit. +** This file is part of the QtGui module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage diff --git a/src/gui/math3d/qmatrix4x4.h b/src/gui/math3d/qmatrix4x4.h index ba7f67f..da1bcba 100644 --- a/src/gui/math3d/qmatrix4x4.h +++ b/src/gui/math3d/qmatrix4x4.h @@ -3,7 +3,7 @@ ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** Contact: Qt Software Information (qt-info@nokia.com) ** -** This file is part of the $MODULE$ of the Qt Toolkit. +** This file is part of the QtGui module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage diff --git a/src/gui/math3d/qquaternion.cpp b/src/gui/math3d/qquaternion.cpp index 96659ea..03f626a 100644 --- a/src/gui/math3d/qquaternion.cpp +++ b/src/gui/math3d/qquaternion.cpp @@ -3,7 +3,7 @@ ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** Contact: Qt Software Information (qt-info@nokia.com) ** -** This file is part of the $MODULE$ of the Qt Toolkit. +** This file is part of the QtGui module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage diff --git a/src/gui/math3d/qquaternion.h b/src/gui/math3d/qquaternion.h index c05c641..b17cf73 100644 --- a/src/gui/math3d/qquaternion.h +++ b/src/gui/math3d/qquaternion.h @@ -3,7 +3,7 @@ ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** Contact: Qt Software Information (qt-info@nokia.com) ** -** This file is part of the $MODULE$ of the Qt Toolkit. +** This file is part of the QtGui module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage diff --git a/src/gui/math3d/qvector2d.cpp b/src/gui/math3d/qvector2d.cpp index c3aaa42..df2519d 100644 --- a/src/gui/math3d/qvector2d.cpp +++ b/src/gui/math3d/qvector2d.cpp @@ -3,7 +3,7 @@ ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** Contact: Qt Software Information (qt-info@nokia.com) ** -** This file is part of the $MODULE$ of the Qt Toolkit. +** This file is part of the QtGui module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage diff --git a/src/gui/math3d/qvector2d.h b/src/gui/math3d/qvector2d.h index b027df4..2be0a11 100644 --- a/src/gui/math3d/qvector2d.h +++ b/src/gui/math3d/qvector2d.h @@ -3,7 +3,7 @@ ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** Contact: Qt Software Information (qt-info@nokia.com) ** -** This file is part of the $MODULE$ of the Qt Toolkit. +** This file is part of the QtGui module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage diff --git a/src/gui/math3d/qvector3d.cpp b/src/gui/math3d/qvector3d.cpp index c83cd60..a5f5c5b 100644 --- a/src/gui/math3d/qvector3d.cpp +++ b/src/gui/math3d/qvector3d.cpp @@ -3,7 +3,7 @@ ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** Contact: Qt Software Information (qt-info@nokia.com) ** -** This file is part of the $MODULE$ of the Qt Toolkit. +** This file is part of the QtGui module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage diff --git a/src/gui/math3d/qvector3d.h b/src/gui/math3d/qvector3d.h index 02873f2..480667a 100644 --- a/src/gui/math3d/qvector3d.h +++ b/src/gui/math3d/qvector3d.h @@ -3,7 +3,7 @@ ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** Contact: Qt Software Information (qt-info@nokia.com) ** -** This file is part of the $MODULE$ of the Qt Toolkit. +** This file is part of the QtGui module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage diff --git a/src/gui/math3d/qvector4d.cpp b/src/gui/math3d/qvector4d.cpp index 010fa53..c5124e2 100644 --- a/src/gui/math3d/qvector4d.cpp +++ b/src/gui/math3d/qvector4d.cpp @@ -3,7 +3,7 @@ ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** Contact: Qt Software Information (qt-info@nokia.com) ** -** This file is part of the $MODULE$ of the Qt Toolkit. +** This file is part of the QtGui module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage diff --git a/src/gui/math3d/qvector4d.h b/src/gui/math3d/qvector4d.h index 8e673f3..e38f4e5 100644 --- a/src/gui/math3d/qvector4d.h +++ b/src/gui/math3d/qvector4d.h @@ -3,7 +3,7 @@ ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** Contact: Qt Software Information (qt-info@nokia.com) ** -** This file is part of the $MODULE$ of the Qt Toolkit. +** This file is part of the QtGui module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage diff --git a/tests/auto/math3d/qmatrixnxn/tst_qmatrixnxn.cpp b/tests/auto/math3d/qmatrixnxn/tst_qmatrixnxn.cpp index 4d51e89..dd3e396 100644 --- a/tests/auto/math3d/qmatrixnxn/tst_qmatrixnxn.cpp +++ b/tests/auto/math3d/qmatrixnxn/tst_qmatrixnxn.cpp @@ -3,7 +3,7 @@ ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** Contact: Qt Software Information (qt-info@nokia.com) ** -** This file is part of the $MODULE$ of the Qt Toolkit. +** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage diff --git a/tests/auto/math3d/qquaternion/tst_qquaternion.cpp b/tests/auto/math3d/qquaternion/tst_qquaternion.cpp index f25f858..5d70e4d 100644 --- a/tests/auto/math3d/qquaternion/tst_qquaternion.cpp +++ b/tests/auto/math3d/qquaternion/tst_qquaternion.cpp @@ -3,7 +3,7 @@ ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** Contact: Qt Software Information (qt-info@nokia.com) ** -** This file is part of the $MODULE$ of the Qt Toolkit. +** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage diff --git a/tests/auto/math3d/qvectornd/tst_qvectornd.cpp b/tests/auto/math3d/qvectornd/tst_qvectornd.cpp index a092fb0..f7d2411 100644 --- a/tests/auto/math3d/qvectornd/tst_qvectornd.cpp +++ b/tests/auto/math3d/qvectornd/tst_qvectornd.cpp @@ -3,7 +3,7 @@ ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** Contact: Qt Software Information (qt-info@nokia.com) ** -** This file is part of the $MODULE$ of the Qt Toolkit. +** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage diff --git a/tests/auto/math3d/shared/math3dincludes.h b/tests/auto/math3d/shared/math3dincludes.h index 1ac0c08..a77090b 100644 --- a/tests/auto/math3d/shared/math3dincludes.h +++ b/tests/auto/math3d/shared/math3dincludes.h @@ -3,7 +3,7 @@ ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** Contact: Qt Software Information (qt-info@nokia.com) ** -** This file is part of the $MODULE$ of the Qt Toolkit. +** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage -- cgit v0.12 From 8b75843c44df306cf5003980f4563d0759dffe7e Mon Sep 17 00:00:00 2001 From: Andreas Aardal Hanssen Date: Wed, 10 Jun 2009 10:54:11 +0200 Subject: Fix tst_QGraphicsProxyWidget::scrollUpdate test, wrong test. It should not be necessary to adjust the expose rectangle by 1 in all directions; the expose has already been adjusted by the scene and view. Reviewed-by: bnilsen --- tests/auto/qgraphicsproxywidget/tst_qgraphicsproxywidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/auto/qgraphicsproxywidget/tst_qgraphicsproxywidget.cpp b/tests/auto/qgraphicsproxywidget/tst_qgraphicsproxywidget.cpp index d856024..fa0e035 100644 --- a/tests/auto/qgraphicsproxywidget/tst_qgraphicsproxywidget.cpp +++ b/tests/auto/qgraphicsproxywidget/tst_qgraphicsproxywidget.cpp @@ -1487,7 +1487,7 @@ void tst_QGraphicsProxyWidget::scrollUpdate() QVector() << QRect(0, 0, 200, 12) << QRect(0, 12, 102, 10)); QCOMPARE(widget->npaints, 2); QCOMPARE(widget->paintEventRegion.rects(), - QVector() << QRect(0, 0, 200, 13) << QRect(0, 13, 103, 10)); + QVector() << QRect(0, 0, 200, 12) << QRect(0, 12, 102, 10)); } void tst_QGraphicsProxyWidget::setWidget_simple() -- cgit v0.12 From f2c4d2fe8a846cfce457512ef1806a7276745590 Mon Sep 17 00:00:00 2001 From: Martin Smith Date: Wed, 10 Jun 2009 12:10:33 +0200 Subject: qdoc: Added new class names for different tables. class="valuelist" is for the table used for enum types. class="alignedsummary" is for summary sections aligned on the name. class="propsummary" is for the property summary section. class="toc" is used for tables of contents. class="generic" is used for all other tables. We might need to break this down more. --- tools/qdoc3/htmlgenerator.cpp | 53 +++++++++++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 20 deletions(-) diff --git a/tools/qdoc3/htmlgenerator.cpp b/tools/qdoc3/htmlgenerator.cpp index fb33de4..44401ed 100644 --- a/tools/qdoc3/htmlgenerator.cpp +++ b/tools/qdoc3/htmlgenerator.cpp @@ -678,13 +678,17 @@ int HtmlGenerator::generateAtom(const Atom *atom, else if (atom->string() == ATOM_LIST_VALUE) { threeColumnEnumValueTable = isThreeColumnEnumValueTable(atom); if (threeColumnEnumValueTable) { - out() << "

\n" - "" - "\n"; + out() << "

ConstantValueDescription
\n" + << "" + << "" + << "\n"; } else { - out() << "

ConstantValueDescription
\n" - << "\n"; + out() << "

ConstantValue
\n" + << "\n"; } } else { @@ -858,14 +862,17 @@ int HtmlGenerator::generateAtom(const Atom *atom, } if (!atom->string().isEmpty()) { if (atom->string().contains("%")) - out() << "

ConstantValue
string() << "\" " + out() << "

string() << "\" " << "align=\"center\" cellpadding=\"2\" " << "cellspacing=\"1\" border=\"0\">\n"; - else - out() << "

\n"; + else { + out() << "

\n"; + } } else { - out() << "

\n"; + out() << "

\n"; } numTableRows = 0; break; @@ -1577,7 +1584,8 @@ void HtmlGenerator::generateTableOfContents(const Node *node, QString tdTag; if (numColumns > 1) { tdTag = "
"; - out() << "

\n" << tdTag << "\n"; + out() << "

\n" + << tdTag << "\n"; } // disable nested links in table of contents @@ -1596,7 +1604,8 @@ void HtmlGenerator::generateTableOfContents(const Node *node, out() << "
    "; sectionNumber.append("1"); } while (sectionNumber.size() < nextLevel); - } else { + } + else { while (sectionNumber.size() > nextLevel) { out() << "
\n"; sectionNumber.removeLast(); @@ -1804,10 +1813,13 @@ void HtmlGenerator::generateClassHierarchy(const Node *relative, } } -void HtmlGenerator::generateAnnotatedList(const Node *relative, CodeMarker *marker, - const QMap &nodeMap) +void +HtmlGenerator::generateAnnotatedList(const Node *relative, + CodeMarker *marker, + const QMap&nodeMap) { - out() << "

\n"; + out() << "

\n"; int row = 0; foreach (const QString &name, nodeMap.keys()) { @@ -1960,7 +1972,7 @@ void HtmlGenerator::generateCompactList(const Node *relative, CodeMarker *marker } firstOffset[NumColumns] = classMap.count(); - out() << "

\n"; + out() << "

\n"; for (k = 0; k < numRows; k++) { out() << "\n"; for (i = 0; i < NumColumns; i++) { @@ -2213,12 +2225,12 @@ void HtmlGenerator::generateSectionList(const Section& section, name_alignment = false; } if (name_alignment) { - out() << "
\n"; } else { if (twoColumn) - out() << "

\n" << "
"; @@ -2513,12 +2525,13 @@ void HtmlGenerator::generateSectionList(const Section& section, bool twoColumn = false; if (style == CodeMarker::SeparateList) { twoColumn = (section.members.count() >= 16); - } else if (section.members.first()->type() == Node::Property) { + } + else if (section.members.first()->type() == Node::Property) { twoColumn = (section.members.count() >= 5); } if (twoColumn) - out() << "

\n" + out() << "

\n" << "
"; out() << "
    \n"; -- cgit v0.12 From 8179a9e2cd52b24c70b194106dd170ed1bb677e4 Mon Sep 17 00:00:00 2001 From: Thierry Bastian Date: Wed, 10 Jun 2009 12:54:53 +0200 Subject: small code cleanup that improves some loops it uses les foreach --- src/gui/itemviews/qabstractitemview.cpp | 4 ++-- src/gui/itemviews/qsortfilterproxymodel.cpp | 7 ++++--- src/gui/itemviews/qstandarditemmodel.cpp | 4 ++-- src/gui/itemviews/qtreeview.cpp | 6 ++++-- src/gui/kernel/qaction.cpp | 25 +++++++++++++++++-------- src/gui/kernel/qwidgetaction.cpp | 4 ++-- src/gui/widgets/qdockarealayout.cpp | 8 ++++---- src/gui/widgets/qdockwidget.cpp | 7 ++++--- src/gui/widgets/qmenubar.cpp | 6 ++++-- 9 files changed, 43 insertions(+), 28 deletions(-) diff --git a/src/gui/itemviews/qabstractitemview.cpp b/src/gui/itemviews/qabstractitemview.cpp index c90216b..d353c2d 100644 --- a/src/gui/itemviews/qabstractitemview.cpp +++ b/src/gui/itemviews/qabstractitemview.cpp @@ -2398,8 +2398,8 @@ void QAbstractItemView::updateEditorGeometries() //we release the editor outside of the loop because it might change the focus and try //to change the d->editors list. - foreach(QWidget *editor, editorsToRelease) { - d->releaseEditor(editor); + for (int i = 0; i < editorsToRelease.count(); ++i) { + d->releaseEditor(editorsToRelease.at(i)); } } diff --git a/src/gui/itemviews/qsortfilterproxymodel.cpp b/src/gui/itemviews/qsortfilterproxymodel.cpp index 96eb6f0..4021c83 100644 --- a/src/gui/itemviews/qsortfilterproxymodel.cpp +++ b/src/gui/itemviews/qsortfilterproxymodel.cpp @@ -884,8 +884,8 @@ void QSortFilterProxyModelPrivate::proxy_item_range( { proxy_low = INT_MAX; proxy_high = INT_MIN; - foreach (int source_item, source_items) { - int proxy_item = source_to_proxy.at(source_item); + for (int i = 0; i < source_items.count(); ++i) { + int proxy_item = source_to_proxy.at(source_items.at(i)); Q_ASSERT(proxy_item != -1); if (proxy_item < proxy_low) proxy_low = proxy_item; @@ -985,7 +985,8 @@ QSet QSortFilterProxyModelPrivate::handle_filter_changed( Q_Q(QSortFilterProxyModel); // Figure out which mapped items to remove QVector source_items_remove; - foreach (int source_item, proxy_to_source) { + for (int i = 0; i < proxy_to_source.count(); ++i) { + const int source_item = proxy_to_source.at(i); if ((orient == Qt::Vertical) ? !q->filterAcceptsRow(source_item, source_parent) : !q->filterAcceptsColumn(source_item, source_parent)) { diff --git a/src/gui/itemviews/qstandarditemmodel.cpp b/src/gui/itemviews/qstandarditemmodel.cpp index d8adbd2..9d0f796 100644 --- a/src/gui/itemviews/qstandarditemmodel.cpp +++ b/src/gui/itemviews/qstandarditemmodel.cpp @@ -2907,8 +2907,8 @@ QMimeData *QStandardItemModel::mimeData(const QModelIndexList &indexes) const QStack stack; itemsSet.reserve(indexes.count()); stack.reserve(indexes.count()); - foreach (const QModelIndex &index, indexes) { - QStandardItem *item = itemFromIndex(index); + for (int i = 0; i < indexes.count(); ++i) { + QStandardItem *item = itemFromIndex(indexes.at(i)); itemsSet << item; stack.push(item); } diff --git a/src/gui/itemviews/qtreeview.cpp b/src/gui/itemviews/qtreeview.cpp index 7837700..965a5c7 100644 --- a/src/gui/itemviews/qtreeview.cpp +++ b/src/gui/itemviews/qtreeview.cpp @@ -2072,7 +2072,8 @@ QModelIndex QTreeView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifie const bool useTopIndex = (cursorAction == MoveUp || cursorAction == MovePrevious); int index = useTopIndex ? INT_MAX : INT_MIN; const QItemSelection selection = d->selectionModel->selection(); - foreach (const QItemSelectionRange &range, selection) { + for (int i = 0; i < selection.count(); ++i) { + const QItemSelectionRange &range = selection.at(i); int candidate = d->viewIndex(useTopIndex ? range.topLeft() : range.bottomRight()); if (candidate >= 0) index = useTopIndex ? qMin(index, candidate) : qMax(index, candidate); @@ -3558,7 +3559,8 @@ QList > QTreeViewPrivate::columnRanges(const QModelIndex &topInd QPair current; current.first = -2; // -1 is not enough because -1+1 = 0 current.second = -2; - foreach (int logicalColumn, logicalIndexes) { + for(int i = 0; i < logicalIndexes.count(); ++i) { + const int logicalColumn = logicalIndexes.at(i); if (current.second + 1 != logicalColumn) { if (current.first != -2) { //let's save the current one diff --git a/src/gui/kernel/qaction.cpp b/src/gui/kernel/qaction.cpp index 051b6a6..f44d207 100644 --- a/src/gui/kernel/qaction.cpp +++ b/src/gui/kernel/qaction.cpp @@ -136,25 +136,31 @@ void QActionPrivate::redoGrab(QShortcutMap &map) void QActionPrivate::redoGrabAlternate(QShortcutMap &map) { Q_Q(QAction); - foreach (int id, alternateShortcutIds) - if (id) + for(int i = 0; i < alternateShortcutIds.count(); ++i) { + if (const int id = alternateShortcutIds.at(i)) map.removeShortcut(id, q); + } alternateShortcutIds.clear(); if (alternateShortcuts.isEmpty()) return; - foreach (const QKeySequence& alternate, alternateShortcuts) { + for(int i = 0; i < alternateShortcuts.count(); ++i) { + const QKeySequence& alternate = alternateShortcuts.at(i); if (!alternate.isEmpty()) alternateShortcutIds.append(map.addShortcut(q, alternate, shortcutContext)); else alternateShortcutIds.append(0); } if (!enabled) { - foreach (int id, alternateShortcutIds) + for(int i = 0; i < alternateShortcutIds.count(); ++i) { + const int id = alternateShortcutIds.at(i); map.setShortcutEnabled(false, id, q); + } } if (!autorepeat) { - foreach (int id, alternateShortcutIds) + for(int i = 0; i < alternateShortcutIds.count(); ++i) { + const int id = alternateShortcutIds.at(i); map.setShortcutAutoRepeat(false, id, q); + } } } @@ -163,9 +169,10 @@ void QActionPrivate::setShortcutEnabled(bool enable, QShortcutMap &map) Q_Q(QAction); if (shortcutId) map.setShortcutEnabled(enable, shortcutId, q); - foreach (int id, alternateShortcutIds) - if (id) + for(int i = 0; i < alternateShortcutIds.count(); ++i) { + if (const int id = alternateShortcutIds.at(i)) map.setShortcutEnabled(enable, id, q); + } } #endif // QT_NO_SHORTCUT @@ -615,8 +622,10 @@ QAction::~QAction() #ifndef QT_NO_SHORTCUT if (d->shortcutId && qApp) { qApp->d_func()->shortcutMap.removeShortcut(d->shortcutId, this); - foreach (int id, d->alternateShortcutIds) + for(int i = 0; i < d->alternateShortcutIds.count(); ++i) { + const int id = d->alternateShortcutIds.at(i); qApp->d_func()->shortcutMap.removeShortcut(id, this); + } } #endif } diff --git a/src/gui/kernel/qwidgetaction.cpp b/src/gui/kernel/qwidgetaction.cpp index efdde5e..cd12029 100644 --- a/src/gui/kernel/qwidgetaction.cpp +++ b/src/gui/kernel/qwidgetaction.cpp @@ -228,8 +228,8 @@ bool QWidgetAction::event(QEvent *event) if (event->type() == QEvent::ActionChanged) { if (d->defaultWidget) d->defaultWidget->setEnabled(isEnabled()); - foreach (QWidget *w, d->createdWidgets) - w->setEnabled(isEnabled()); + for (int i = 0; i < d->createdWidgets.count(); ++i) + d->createdWidgets.at(i)->setEnabled(isEnabled()); } return QAction::event(event); } diff --git a/src/gui/widgets/qdockarealayout.cpp b/src/gui/widgets/qdockarealayout.cpp index 4f0ec1e..58e8f9c 100644 --- a/src/gui/widgets/qdockarealayout.cpp +++ b/src/gui/widgets/qdockarealayout.cpp @@ -2202,8 +2202,8 @@ QSet QDockAreaLayoutInfo::usedSeparatorWidgets() const { QSet result; - foreach (QWidget *sepWidget, separatorWidgets) - result << sepWidget; + for (int i = 0; i < separatorWidgets.count(); ++i) + result << separatorWidgets.at(i); for (int i = 0; i < item_list.count(); ++i) { const QDockAreaLayoutItem &item = item_list.at(i); @@ -3244,8 +3244,8 @@ QSet QDockAreaLayout::usedSeparatorWidgets() const { QSet result; - foreach (QWidget *sepWidget, separatorWidgets) - result << sepWidget; + for (int i = 0; i < separatorWidgets.count(); ++i) + result << separatorWidgets.at(i); for (int i = 0; i < QInternal::DockCount; ++i) { const QDockAreaLayoutInfo &dock = docks[i]; result += dock.usedSeparatorWidgets(); diff --git a/src/gui/widgets/qdockwidget.cpp b/src/gui/widgets/qdockwidget.cpp index d573b8b..6a0c879 100644 --- a/src/gui/widgets/qdockwidget.cpp +++ b/src/gui/widgets/qdockwidget.cpp @@ -221,7 +221,8 @@ void QDockWidgetLayout::addItem(QLayoutItem*) QLayoutItem *QDockWidgetLayout::itemAt(int index) const { int cnt = 0; - foreach (QLayoutItem *item, item_list) { + for (int i = 0; i < item_list.count(); ++i) { + QLayoutItem *item = item_list.at(i); if (item == 0) continue; if (index == cnt++) @@ -250,8 +251,8 @@ QLayoutItem *QDockWidgetLayout::takeAt(int index) int QDockWidgetLayout::count() const { int result = 0; - foreach (QLayoutItem *item, item_list) { - if (item != 0) + for (int i = 0; i < item_list.count(); ++i) { + if (item_list.at(i)) ++result; } return result; diff --git a/src/gui/widgets/qmenubar.cpp b/src/gui/widgets/qmenubar.cpp index cffc3d5..fc7e901 100644 --- a/src/gui/widgets/qmenubar.cpp +++ b/src/gui/widgets/qmenubar.cpp @@ -220,7 +220,8 @@ void QMenuBarPrivate::updateGeometries() //we try to see if the actions will fit there bool hasHiddenActions = false; - foreach(QAction *action, actionList) { + for (int i = 0; i < actionList.count(); ++i) { + QAction *action = actionList.at(i); if (!menuRect.contains(actionRect(action))) { hasHiddenActions = true; break; @@ -230,7 +231,8 @@ void QMenuBarPrivate::updateGeometries() //...and if not, determine the ones that fit on the menu with the extension visible if (hasHiddenActions) { menuRect = this->menuRect(true); - foreach(QAction *action, actionList) { + for (int i = 0; i < actionList.count(); ++i) { + QAction *action = actionList.at(i); if (!menuRect.contains(actionRect(action))) { hiddenActions.append(action); } -- cgit v0.12 From 53632d45ca64ad4c20d4302e0826c0234877dd69 Mon Sep 17 00:00:00 2001 From: Andreas Aardal Hanssen Date: Wed, 10 Jun 2009 13:26:23 +0200 Subject: Revert "implement equality operator in a more sane way" This reverts commit 07dca7a30d4bd1efd8032915700420cca3fd60fa. Move the equality operator code back in (qFuzzyCompare) to avoid breaking many autotests. The change should go back in later on, possibly supplemented by a qFuzzyCompare(QTransform) function. But until we can figure out how to not break everything this patch has to wait. Reviewed-by: Lars --- src/gui/painting/qtransform.cpp | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/gui/painting/qtransform.cpp b/src/gui/painting/qtransform.cpp index bd2ea31..86e594c 100644 --- a/src/gui/painting/qtransform.cpp +++ b/src/gui/painting/qtransform.cpp @@ -700,15 +700,11 @@ QTransform & QTransform::rotateRadians(qreal a, Qt::Axis axis) */ bool QTransform::operator==(const QTransform &o) const { - return affine._m11 == o.affine._m11 && - affine._m12 == o.affine._m12 && - affine._m21 == o.affine._m21 && - affine._m22 == o.affine._m22 && - affine._dx == o.affine._dx && - affine._dy == o.affine._dy && - m_13 == o.m_13 && - m_23 == o.m_23 && - m_33 == o.m_33; +#define qFZ qFuzzyCompare + return qFZ(affine._m11, o.affine._m11) && qFZ(affine._m12, o.affine._m12) && qFZ(m_13, o.m_13) + && qFZ(affine._m21, o.affine._m21) && qFZ(affine._m22, o.affine._m22) && qFZ(m_23, o.m_23) + && qFZ(affine._dx, o.affine._dx) && qFZ(affine._dy, o.affine._dy) && qFZ(m_33, o.m_33); +#undef qFZ } /*! -- cgit v0.12 From 62725a02652cee576efe055d1371765945045026 Mon Sep 17 00:00:00 2001 From: Thomas Zander Date: Wed, 10 Jun 2009 13:31:06 +0200 Subject: add some api docs to clarify what collate does --- src/gui/painting/qprinter.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/gui/painting/qprinter.cpp b/src/gui/painting/qprinter.cpp index ba208fd..ce33893 100644 --- a/src/gui/painting/qprinter.cpp +++ b/src/gui/painting/qprinter.cpp @@ -1308,6 +1308,9 @@ void QPrinter::setNumCopies(int numCopies) Returns true if collation is turned on when multiple copies is selected. Returns false if it is turned off when multiple copies is selected. + When collating is turned off the printing of each individual page will be repeated + the numCopies() amount before the next page is started. With collating turned on + all pages are printed before the next copy of those pages is started. \sa setCollateCopies() */ -- cgit v0.12 From 14f72183fbe1c7fad7c5434b2af032cc51436f5e Mon Sep 17 00:00:00 2001 From: Andreas Aardal Hanssen Date: Wed, 10 Jun 2009 14:08:23 +0200 Subject: Revert "greatly speed up QTransform::mapRect() for projective transforms" This reverts commit 72e083c98c3adb07bb1578fb7f28f121fc3f34ac. This test broke the tst_QTransform::projectivePathMapping autotest. Lars is looking into it; for now we take the patch out. Reviewed-by: Lars --- src/gui/painting/qtransform.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/gui/painting/qtransform.cpp b/src/gui/painting/qtransform.cpp index 86e594c..c00012a 100644 --- a/src/gui/painting/qtransform.cpp +++ b/src/gui/painting/qtransform.cpp @@ -1788,7 +1788,7 @@ QRect QTransform::mapRect(const QRect &rect) const y -= h; } return QRect(x, y, w, h); - } else { + } else if (t < TxProject) { // see mapToPolygon for explanations of the algorithm. qreal x = 0, y = 0; MAP(rect.left(), rect.top(), x, y); @@ -1812,6 +1812,10 @@ QRect QTransform::mapRect(const QRect &rect) const xmax = qMax(xmax, x); ymax = qMax(ymax, y); return QRect(qRound(xmin), qRound(ymin), qRound(xmax)-qRound(xmin), qRound(ymax)-qRound(ymin)); + } else { + QPainterPath path; + path.addRect(rect); + return map(path).boundingRect().toRect(); } } @@ -1854,7 +1858,7 @@ QRectF QTransform::mapRect(const QRectF &rect) const y -= h; } return QRectF(x, y, w, h); - } else { + } else if (t < TxProject) { qreal x = 0, y = 0; MAP(rect.x(), rect.y(), x, y); qreal xmin = x; @@ -1877,6 +1881,10 @@ QRectF QTransform::mapRect(const QRectF &rect) const xmax = qMax(xmax, x); ymax = qMax(ymax, y); return QRectF(xmin, ymin, xmax-xmin, ymax - ymin); + } else { + QPainterPath path; + path.addRect(rect); + return map(path).boundingRect(); } } -- cgit v0.12 From 08618c4d4e7b3d99ffa2b56ea03fa4e25de101bd Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Wed, 10 Jun 2009 14:41:33 +0200 Subject: Fix some possible double connected signals Task-number: 250147 Reviewed-by: Thierry --- src/gui/itemviews/qtableview.cpp | 6 +++--- src/gui/itemviews/qtreeview.cpp | 9 ++------- src/gui/widgets/qtoolbarlayout.cpp | 2 +- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/src/gui/itemviews/qtableview.cpp b/src/gui/itemviews/qtableview.cpp index 0bded54..454b1f5 100644 --- a/src/gui/itemviews/qtableview.cpp +++ b/src/gui/itemviews/qtableview.cpp @@ -1844,14 +1844,14 @@ void QTableView::setSortingEnabled(bool enable) disconnect(horizontalHeader(), SIGNAL(sectionPressed(int)), this, SLOT(selectColumn(int))); connect(horizontalHeader(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), - this, SLOT(sortByColumn(int))); + this, SLOT(sortByColumn(int)), Qt::UniqueConnection); sortByColumn(horizontalHeader()->sortIndicatorSection(), horizontalHeader()->sortIndicatorOrder()); } else { connect(d->horizontalHeader, SIGNAL(sectionEntered(int)), - this, SLOT(_q_selectColumn(int))); + this, SLOT(_q_selectColumn(int)), Qt::UniqueConnection); connect(horizontalHeader(), SIGNAL(sectionPressed(int)), - this, SLOT(selectColumn(int))); + this, SLOT(selectColumn(int)), Qt::UniqueConnection); disconnect(horizontalHeader(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), this, SLOT(sortByColumn(int))); } diff --git a/src/gui/itemviews/qtreeview.cpp b/src/gui/itemviews/qtreeview.cpp index 965a5c7..9910118 100644 --- a/src/gui/itemviews/qtreeview.cpp +++ b/src/gui/itemviews/qtreeview.cpp @@ -238,11 +238,6 @@ void QTreeView::setModel(QAbstractItemModel *model) connect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(rowsRemoved(QModelIndex,int,int))); - connect(d->model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)), - this, SLOT(_q_columnsAboutToBeRemoved(QModelIndex,int,int))); - connect(d->model, SIGNAL(columnsRemoved(QModelIndex,int,int)), - this, SLOT(_q_columnsRemoved(QModelIndex,int,int))); - connect(d->model, SIGNAL(modelAboutToBeReset()), SLOT(_q_modelAboutToBeReset())); if (d->sortingEnabled) @@ -3072,16 +3067,16 @@ void QTreeViewPrivate::_q_modelAboutToBeReset() void QTreeViewPrivate::_q_columnsAboutToBeRemoved(const QModelIndex &parent, int start, int end) { - Q_UNUSED(parent); if (start <= 0 && 0 <= end) viewItems.clear(); + QAbstractItemViewPrivate::_q_columnsAboutToBeRemoved(parent, start, end); } void QTreeViewPrivate::_q_columnsRemoved(const QModelIndex &parent, int start, int end) { - Q_UNUSED(parent); if (start <= 0 && 0 <= end) doDelayedItemsLayout(); + QAbstractItemViewPrivate::_q_columnsRemoved(parent, start, end); } void QTreeViewPrivate::layout(int i) diff --git a/src/gui/widgets/qtoolbarlayout.cpp b/src/gui/widgets/qtoolbarlayout.cpp index 0bfa493..0af2b65 100644 --- a/src/gui/widgets/qtoolbarlayout.cpp +++ b/src/gui/widgets/qtoolbarlayout.cpp @@ -128,7 +128,7 @@ void QToolBarLayout::setUsePopupMenu(bool set) invalidate(); if (!set) { QObject::connect(extension, SIGNAL(clicked(bool)), - this, SLOT(setExpanded(bool))); + this, SLOT(setExpanded(bool)), Qt::UniqueConnection); extension->setPopupMode(QToolButton::DelayedPopup); extension->setMenu(0); delete popupMenu; -- cgit v0.12 From 686700203aa9deeafba3bae826c7caec6d6916fd Mon Sep 17 00:00:00 2001 From: Alexis Menard Date: Wed, 10 Jun 2009 14:44:52 +0200 Subject: Move declaration of QFileInfoPrivate in a separate file _p and add an auto-test when we copy file infos. Reviewed-by: ogoffart --- src/corelib/io/io.pri | 1 + src/corelib/io/qfileinfo.cpp | 65 +---------------- src/corelib/io/qfileinfo_p.h | 126 +++++++++++++++++++++++++++++++++ tests/auto/qfileinfo/tst_qfileinfo.cpp | 56 +++++++++++++++ 4 files changed, 184 insertions(+), 64 deletions(-) create mode 100644 src/corelib/io/qfileinfo_p.h diff --git a/src/corelib/io/io.pri b/src/corelib/io/io.pri index 8f37e25..5033b21 100644 --- a/src/corelib/io/io.pri +++ b/src/corelib/io/io.pri @@ -10,6 +10,7 @@ HEADERS += \ io/qdiriterator.h \ io/qfile.h \ io/qfileinfo.h \ + io/qfileinfo_p.h \ io/qiodevice.h \ io/qiodevice_p.h \ io/qnoncontiguousbytedevice_p.h \ diff --git a/src/corelib/io/qfileinfo.cpp b/src/corelib/io/qfileinfo.cpp index 36b1ed8..4f1b943 100644 --- a/src/corelib/io/qfileinfo.cpp +++ b/src/corelib/io/qfileinfo.cpp @@ -48,73 +48,10 @@ #include "qatomic.h" #include "qhash.h" #include "qdir.h" +#include "qfileinfo_p.h" QT_BEGIN_NAMESPACE -class QFileInfoPrivate -{ -public: - QFileInfoPrivate(const QFileInfo *copy=0); - ~QFileInfoPrivate(); - - void initFileEngine(const QString &); - - enum Access { - ReadAccess, - WriteAccess, - ExecuteAccess - }; - bool hasAccess(Access access) const; - - uint getFileFlags(QAbstractFileEngine::FileFlags) const; - QDateTime &getFileTime(QAbstractFileEngine::FileTime) const; - QString getFileName(QAbstractFileEngine::FileName) const; - - enum { CachedFileFlags=0x01, CachedLinkTypeFlag=0x02, CachedBundleTypeFlag=0x04, - CachedMTime=0x10, CachedCTime=0x20, CachedATime=0x40, - CachedSize =0x08 }; - struct Data { - inline Data() - : ref(1), fileEngine(0), cache_enabled(1) - { clear(); } - inline Data(const Data ©) - : ref(1), fileEngine(QAbstractFileEngine::create(copy.fileName)), - fileName(copy.fileName), cache_enabled(copy.cache_enabled) - { clear(); } - inline ~Data() { delete fileEngine; } - inline void clearFlags() { - fileFlags = 0; - cachedFlags = 0; - if (fileEngine) - (void)fileEngine->fileFlags(QFSFileEngine::Refresh); - } - inline void clear() { - fileNames.clear(); - clearFlags(); - } - mutable QAtomicInt ref; - - QAbstractFileEngine *fileEngine; - mutable QString fileName; - mutable QHash fileNames; - - mutable uint cachedFlags : 31; - mutable uint cache_enabled : 1; - mutable uint fileFlags; - mutable qint64 fileSize; - mutable QDateTime fileTimes[3]; - inline bool getCachedFlag(uint c) const - { return cache_enabled ? (cachedFlags & c) : 0; } - inline void setCachedFlag(uint c) - { if (cache_enabled) cachedFlags |= c; } - } *data; - inline void reset() { - detach(); - data->clear(); - } - void detach(); -}; - QFileInfoPrivate::QFileInfoPrivate(const QFileInfo *copy) { if(copy) { diff --git a/src/corelib/io/qfileinfo_p.h b/src/corelib/io/qfileinfo_p.h new file mode 100644 index 0000000..8155bcb --- /dev/null +++ b/src/corelib/io/qfileinfo_p.h @@ -0,0 +1,126 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QFILEINFO_P_H +#define QFILEINFO_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qfileinfo.h" + +QT_BEGIN_NAMESPACE + +class QFileInfoPrivate +{ +public: + QFileInfoPrivate(const QFileInfo *copy=0); + ~QFileInfoPrivate(); + + void initFileEngine(const QString &); + + enum Access { + ReadAccess, + WriteAccess, + ExecuteAccess + }; + bool hasAccess(Access access) const; + + uint getFileFlags(QAbstractFileEngine::FileFlags) const; + QDateTime &getFileTime(QAbstractFileEngine::FileTime) const; + QString getFileName(QAbstractFileEngine::FileName) const; + + enum { CachedFileFlags=0x01, CachedLinkTypeFlag=0x02, CachedBundleTypeFlag=0x04, + CachedMTime=0x10, CachedCTime=0x20, CachedATime=0x40, + CachedSize =0x08 }; + struct Data { + inline Data() + : ref(1), fileEngine(0), cache_enabled(1) + { clear(); } + inline Data(const Data ©) + : ref(1), fileEngine(QAbstractFileEngine::create(copy.fileName)), + fileName(copy.fileName), cache_enabled(copy.cache_enabled) + { clear(); } + inline ~Data() { delete fileEngine; } + inline void clearFlags() { + fileFlags = 0; + cachedFlags = 0; + if (fileEngine) + (void)fileEngine->fileFlags(QFSFileEngine::Refresh); + } + inline void clear() { + fileNames.clear(); + clearFlags(); + } + mutable QAtomicInt ref; + + QAbstractFileEngine *fileEngine; + mutable QString fileName; + mutable QHash fileNames; + + mutable uint cachedFlags : 31; + mutable uint cache_enabled : 1; + mutable uint fileFlags; + mutable qint64 fileSize; + mutable QDateTime fileTimes[3]; + inline bool getCachedFlag(uint c) const + { return cache_enabled ? (cachedFlags & c) : 0; } + inline void setCachedFlag(uint c) + { if (cache_enabled) cachedFlags |= c; } + } *data; + inline void reset() { + detach(); + data->clear(); + } + void detach(); +}; + +QT_END_NAMESPACE + +#endif // QFILEINFO_P_H diff --git a/tests/auto/qfileinfo/tst_qfileinfo.cpp b/tests/auto/qfileinfo/tst_qfileinfo.cpp index 3d7e6f8..cccdd64 100644 --- a/tests/auto/qfileinfo/tst_qfileinfo.cpp +++ b/tests/auto/qfileinfo/tst_qfileinfo.cpp @@ -61,6 +61,7 @@ #include #include "../network-settings.h" +#include //TESTED_CLASS= //TESTED_FILES= @@ -75,6 +76,9 @@ public: private slots: void getSetCheck(); + + void copy(); + void isFile_data(); void isFile(); @@ -178,6 +182,58 @@ void tst_QFileInfo::getSetCheck() QCOMPARE(true, obj1.caching()); } +static QFileInfoPrivate* getPrivate(QFileInfo &info) +{ + return (*reinterpret_cast(&info)); +} + +void tst_QFileInfo::copy() +{ + QTemporaryFile *t; + t = new QTemporaryFile; + t->open(); + QFileInfo info(t->fileName()); + QVERIFY(info.exists()); + + //copy constructor + QFileInfo info2(info); + QFileInfoPrivate *privateInfo = getPrivate(info); + QFileInfoPrivate *privateInfo2 = getPrivate(info2); + QCOMPARE(privateInfo->data, privateInfo2->data); + + //operator = + QFileInfo info3 = info; + QFileInfoPrivate *privateInfo3 = getPrivate(info3); + QCOMPARE(privateInfo->data, privateInfo3->data); + QCOMPARE(privateInfo2->data, privateInfo3->data); + + //refreshing info3 will detach it + QFile file(info.absoluteFilePath()); + QVERIFY(file.open(QFile::WriteOnly)); + QCOMPARE(file.write("JAJAJAA"), qint64(7)); + file.flush(); + + QTest::qWait(250); +#if defined(Q_OS_WIN) || defined(Q_OS_WINCE) + if (QSysInfo::windowsVersion() & QSysInfo::WV_VISTA || + QSysInfo::windowsVersion() & QSysInfo::WV_CE_based) + file.close(); +#endif +#if defined(Q_OS_WINCE) + // On Windows CE we need to close the file. + // Otherwise the content will be cached and not + // flushed to the storage, although we flushed it + // manually!!! CE has interim cache, we cannot influence. + QTest::qWait(5000); +#endif + info3.refresh(); + QVERIFY(privateInfo->data != privateInfo3->data); + QVERIFY(privateInfo2->data != privateInfo3->data); + QCOMPARE(privateInfo->data, privateInfo2->data); + + +} + tst_QFileInfo::tst_QFileInfo() { } -- cgit v0.12 From a66525c2e4c760f8ceda344cd7252431ed263654 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Fri, 29 May 2009 11:16:20 +0200 Subject: Use a linked list for the senders list inside QObject Speed up the disconnection and object destruction Reviewed-by: Brad --- src/corelib/kernel/qobject.cpp | 67 +++++++++++++++++++++++------------------- src/corelib/kernel/qobject_p.h | 5 +++- 2 files changed, 40 insertions(+), 32 deletions(-) diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index 5e33a71..e953bcb 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -123,7 +123,7 @@ extern "C" Q_CORE_EXPORT void qt_removeObject(QObject *) } QObjectPrivate::QObjectPrivate(int version) - : threadData(0), currentSender(0), currentChildBeingDeleted(0), connectionLists(0) + : threadData(0), currentSender(0), currentChildBeingDeleted(0), connectionLists(0), senders(0) { if (version != QObjectPrivateVersion) qFatal("Cannot mix incompatible Qt libraries"); @@ -287,8 +287,8 @@ QObjectList QObjectPrivate::senderList() const { QObjectList returnValue; QMutexLocker locker(signalSlotLock(q_func())); - for (int i = 0; i < senders.count(); ++i) - returnValue << senders.at(i)->sender; + for (Connection *c = senders; c; c = c->next) + returnValue << c->sender; return returnValue; } @@ -756,8 +756,10 @@ QObject::~QObject() QMutex *m = signalSlotLock(c->receiver); bool needToUnlock = QOrderedMutexLocker::relock(locker.mutex(), m); c = connectionList[i]; - if (c->receiver) - c->receiver->d_func()->senders.removeOne(c); + if (c->receiver) { + *c->prev = c->next; + if (c->next) c->next->prev = c->prev; + } if (needToUnlock) m->unlock(); @@ -774,29 +776,25 @@ QObject::~QObject() } // disconnect all senders - for (int i = 0; i < d->senders.count(); ) { - QObjectPrivate::Connection *s = d->senders[i]; - - QMutex *m = signalSlotLock(s->sender); + QObjectPrivate::Connection *node = d->senders; + while (node) { + QMutex *m = signalSlotLock(node->sender); + node->prev = &node; bool needToUnlock = QOrderedMutexLocker::relock(locker.mutex(), m); - if (m < locker.mutex()) { - if (i >= d->senders.count() || s != d->senders[i]) { - if (needToUnlock) - m->unlock(); - continue; - } + //the node has maybe been removed while the mutex was unlocked in relock? + if (!node || signalSlotLock(node->sender) != m) { + m->unlock(); + continue; } - s->receiver = 0; - QObjectConnectionListVector *senderLists = s->sender->d_func()->connectionLists; + node->receiver = 0; + QObjectConnectionListVector *senderLists = node->sender->d_func()->connectionLists; if (senderLists) senderLists->dirty = true; if (needToUnlock) m->unlock(); - ++i; + node = node->next; } - - d->senders.clear(); } if (d->pendTimer) { @@ -2281,8 +2279,8 @@ QObject *QObject::sender() const // Return 0 if d->currentSender isn't in d->senders bool found = false; - for (int i = 0; !found && i < d->senders.count(); ++i) - found = (d->senders.at(i)->sender == d->currentSender->sender); + for (QObjectPrivate::Connection *c = d->senders; c && !found; c = c->next) + found = (c->sender == d->currentSender->sender); if (!found) return 0; return d->currentSender->sender; @@ -2799,9 +2797,13 @@ bool QMetaObject::connect(const QObject *sender, int signal_index, c->method = method_index; c->connectionType = type; c->argumentTypes = types; + c->prev = &r->d_func()->senders; + c->next = *c->prev; + *c->prev = c; + if (c->next) + c->next->prev = &c->next; s->d_func()->addConnection(signal_index, c); - r->d_func()->senders.append(c); if (signal_index < 0) sender->d_func()->connectedSignals = ~0u; @@ -2851,8 +2853,10 @@ bool QMetaObject::disconnect(const QObject *sender, int signal_index, needToUnlock = QOrderedMutexLocker::relock(senderMutex, m); c = connectionList[i]; } - if (c->receiver) - c->receiver->d_func()->senders.removeOne(c); + if (c->receiver) { + *c->prev = c->next; + if (c->next) c->next->prev = c->prev; + } if (needToUnlock) m->unlock(); @@ -2878,8 +2882,10 @@ bool QMetaObject::disconnect(const QObject *sender, int signal_index, needToUnlock = QOrderedMutexLocker::relock(senderMutex, m); c = connectionList[i]; } - if (c->receiver) - c->receiver->d_func()->senders.removeOne(c); + if (c->receiver) { + *c->prev = c->next; + if (c->next) c->next->prev = c->prev; + } if (needToUnlock) m->unlock(); @@ -3417,9 +3423,8 @@ void QObject::dumpObjectInfo() // now look for connections where this object is the receiver qDebug(" SIGNALS IN"); - if (!d->senders.isEmpty()) { - for (int i = 0; i < d->senders.count(); ++i) { - const QObjectPrivate::Connection *s = d->senders.at(i); + if (d->senders) { + for (QObjectPrivate::Connection *s = d->senders; s; s = s->next) const QMetaMethod slot = metaObject()->method(s->method); qDebug(" <-- %s::%s %s", s->sender->metaObject()->className(), @@ -3427,7 +3432,7 @@ void QObject::dumpObjectInfo() slot.signature()); } } else { - qDebug(" "); + qDebug(" "); } #endif } diff --git a/src/corelib/kernel/qobject_p.h b/src/corelib/kernel/qobject_p.h index 96d79af..d699061 100644 --- a/src/corelib/kernel/qobject_p.h +++ b/src/corelib/kernel/qobject_p.h @@ -152,6 +152,9 @@ public: int method; uint connectionType : 3; // 0 == auto, 1 == direct, 2 == queued, 4 == blocking QBasicAtomicPointer argumentTypes; + //senders linked list + Connection *next; + Connection **prev; ~Connection(); }; typedef QList ConnectionList; @@ -160,7 +163,7 @@ public: void addConnection(int signal, Connection *c); void cleanConnectionLists(); - ConnectionList senders; + Connection *senders; //linked list; static Sender *setCurrentSender(QObject *receiver, Sender *sender); -- cgit v0.12 From 1a5e7171b9da383ca5f6be92b7cb6e502fd79fc4 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Wed, 3 Jun 2009 20:47:06 +0200 Subject: Avoid locking and search on the global hash if there is no QPointer As less than 10% of the object have QPointers, we can avoid locking if we know there is no QPointer. And keeping track of which object has a QPointer is easy. Reviewed-by: Brad --- src/corelib/kernel/qobject.cpp | 22 +++++++++++++++++++--- src/corelib/kernel/qobject.h | 3 ++- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index e953bcb..a095e0a 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -143,6 +143,7 @@ QObjectPrivate::QObjectPrivate(int version) inEventHandler = false; inThreadChangeEvent = false; deleteWatch = 0; + hasGuards = false; } QObjectPrivate::~QObjectPrivate() @@ -359,6 +360,7 @@ void QMetaObject::addGuard(QObject **ptr) return; } QMutexLocker locker(guardHashLock()); + QObjectPrivate::get(*ptr)->hasGuards = true; hash->insert(*ptr, ptr); } @@ -374,12 +376,17 @@ void QMetaObject::removeGuard(QObject **ptr) QMutexLocker locker(guardHashLock()); GuardHash::iterator it = hash->find(*ptr); const GuardHash::iterator end = hash->end(); + bool more = false; //if the QObject has more pointer attached to it. for (; it.key() == *ptr && it != end; ++it) { if (it.value() == ptr) { - (void) hash->erase(it); + it = hash->erase(it); + if (!more) more = (it != end && it.key() == *ptr); break; } + more = true; } + if (!more) + QObjectPrivate::get(*ptr)->hasGuards = false; } /*!\internal @@ -393,24 +400,33 @@ void QMetaObject::changeGuard(QObject **ptr, QObject *o) } QMutexLocker locker(guardHashLock()); if (*ptr) { + bool more = false; //if the QObject has more pointer attached to it. GuardHash::iterator it = hash->find(*ptr); const GuardHash::iterator end = hash->end(); for (; it.key() == *ptr && it != end; ++it) { if (it.value() == ptr) { - (void) hash->erase(it); + it = hash->erase(it); + if (!more) more = (it != end && it.key() == *ptr); break; } + more = true; } + if (!more) + QObjectPrivate::get(*ptr)->hasGuards = false; } *ptr = o; - if (*ptr) + if (*ptr) { hash->insert(*ptr, ptr); + QObjectPrivate::get(*ptr)->hasGuards = true; + } } /*! \internal */ void QObjectPrivate::clearGuards(QObject *object) { + if (!QObjectPrivate::get(object)->hasGuards) + return; GuardHash *hash = guardHash(); if (hash) { QMutexLocker locker(guardHashLock()); diff --git a/src/corelib/kernel/qobject.h b/src/corelib/kernel/qobject.h index dbec0a6..b1f41ad 100644 --- a/src/corelib/kernel/qobject.h +++ b/src/corelib/kernel/qobject.h @@ -106,7 +106,8 @@ public: uint receiveChildEvents : 1; uint inEventHandler : 1; uint inThreadChangeEvent : 1; - uint unused : 23; + uint hasGuards : 1; //true iff there is one or more QPointer attached to this object + uint unused : 22; int postedEvents; }; -- cgit v0.12 From dd3ee408148368a6f900844afc68fff9d86c2e8c Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Wed, 10 Jun 2009 15:44:11 +0200 Subject: Compile with debug enabled --- src/corelib/kernel/qobject.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index a095e0a..55d70c1 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -3440,7 +3440,7 @@ void QObject::dumpObjectInfo() qDebug(" SIGNALS IN"); if (d->senders) { - for (QObjectPrivate::Connection *s = d->senders; s; s = s->next) + for (QObjectPrivate::Connection *s = d->senders; s; s = s->next) { const QMetaMethod slot = metaObject()->method(s->method); qDebug(" <-- %s::%s %s", s->sender->metaObject()->className(), -- cgit v0.12 From 09faf56a2e44b4dfa1b341ced75803100483834f Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Tue, 9 Jun 2009 23:44:32 +0300 Subject: Added QAbstractItemModelPrivate::canConvertToDouble(). And changed QTreeWidgetItem::operator<() and QTableWidgetItem::operator<() to use it Merge-request: 631 Reviewed-by: Olivier Goffart --- src/corelib/kernel/qabstractitemmodel.cpp | 17 +++++++++++++++++ src/corelib/kernel/qabstractitemmodel_p.h | 1 + src/gui/itemviews/qtablewidget.cpp | 20 +------------------- src/gui/itemviews/qtablewidget_p.h | 1 - src/gui/itemviews/qtreewidget.cpp | 25 +------------------------ src/gui/itemviews/qtreewidget_p.h | 1 - 6 files changed, 20 insertions(+), 45 deletions(-) diff --git a/src/corelib/kernel/qabstractitemmodel.cpp b/src/corelib/kernel/qabstractitemmodel.cpp index 935c0aa..0a84ddb 100644 --- a/src/corelib/kernel/qabstractitemmodel.cpp +++ b/src/corelib/kernel/qabstractitemmodel.cpp @@ -467,6 +467,23 @@ QAbstractItemModel *QAbstractItemModelPrivate::staticEmptyModel() return qEmptyModel(); } +bool QAbstractItemModelPrivate::canConvertToDouble(const QVariant &value) +{ + switch (value.type()) { + case QVariant::Bool: + case QVariant::Int: + case QVariant::UInt: + case QVariant::LongLong: + case QVariant::ULongLong: + case QVariant::Double: + case QVariant::Char: + return true; + default: + return false; + } + return false; +} + void QAbstractItemModelPrivate::removePersistentIndexData(QPersistentModelIndexData *data) { if (data->index.isValid()) { diff --git a/src/corelib/kernel/qabstractitemmodel_p.h b/src/corelib/kernel/qabstractitemmodel_p.h index 27f1b28..70c35cb 100644 --- a/src/corelib/kernel/qabstractitemmodel_p.h +++ b/src/corelib/kernel/qabstractitemmodel_p.h @@ -89,6 +89,7 @@ public: void columnsAboutToBeRemoved(const QModelIndex &parent, int first, int last); void columnsRemoved(const QModelIndex &parent, int first, int last); static QAbstractItemModel *staticEmptyModel(); + static bool canConvertToDouble(const QVariant &value); inline QModelIndex createIndex(int row, int column, void *data = 0) const { return q_func()->createIndex(row, column, data); diff --git a/src/gui/itemviews/qtablewidget.cpp b/src/gui/itemviews/qtablewidget.cpp index 8cb2e55..072e435 100644 --- a/src/gui/itemviews/qtablewidget.cpp +++ b/src/gui/itemviews/qtablewidget.cpp @@ -530,24 +530,6 @@ void QTableModel::sort(int column, Qt::SortOrder order) emit layoutChanged(); } -bool QTableModel::canConvertToDouble(const QVariant &value) -{ - switch (value.type()) { - case QVariant::Bool: - case QVariant::Int: - case QVariant::UInt: - case QVariant::LongLong: - case QVariant::ULongLong: - case QVariant::Double: - case QVariant::Char: - return true; - default: - return false; - } - return false; -} - - /* \internal @@ -1410,7 +1392,7 @@ QVariant QTableWidgetItem::data(int role) const bool QTableWidgetItem::operator<(const QTableWidgetItem &other) const { const QVariant v1 = data(Qt::DisplayRole), v2 = other.data(Qt::DisplayRole); - if (QTableModel::canConvertToDouble(v1) && QTableModel::canConvertToDouble(v2)) + if (QAbstractItemModelPrivate::canConvertToDouble(v1) && QAbstractItemModelPrivate::canConvertToDouble(v2)) return v1.toDouble() < v2.toDouble(); return v1.toString() < v2.toString(); } diff --git a/src/gui/itemviews/qtablewidget_p.h b/src/gui/itemviews/qtablewidget_p.h index 2e1dab6..d8bfcc5 100644 --- a/src/gui/itemviews/qtablewidget_p.h +++ b/src/gui/itemviews/qtablewidget_p.h @@ -144,7 +144,6 @@ public: const QPair &right); static bool itemGreaterThan(const QPair &left, const QPair &right); - static bool canConvertToDouble(const QVariant &value); void ensureSorted(int column, Qt::SortOrder order, int start, int end); QVector columnItems(int column) const; diff --git a/src/gui/itemviews/qtreewidget.cpp b/src/gui/itemviews/qtreewidget.cpp index 1c87580..5604f8d 100644 --- a/src/gui/itemviews/qtreewidget.cpp +++ b/src/gui/itemviews/qtreewidget.cpp @@ -695,29 +695,6 @@ bool QTreeModel::itemGreaterThan(const QPair &left, } /*! - \internal - - Returns true if the type of the variant \a value - can be casted as double. -*/ -bool QTreeModel::canConvertToDouble(const QVariant &value) -{ - switch (value.type()) { - case QVariant::Bool: - case QVariant::Int: - case QVariant::UInt: - case QVariant::LongLong: - case QVariant::ULongLong: - case QVariant::Double: - case QVariant::Char: - return true; - default: - return false; - } - return false; -} - -/*! \internal */ QList::iterator QTreeModel::sortedInsertionIterator( @@ -1812,7 +1789,7 @@ bool QTreeWidgetItem::operator<(const QTreeWidgetItem &other) const int column = view ? view->sortColumn() : 0; const QVariant v1 = data(column, Qt::DisplayRole); const QVariant v2 = other.data(column, Qt::DisplayRole); - if (QTreeModel::canConvertToDouble(v1) && QTreeModel::canConvertToDouble(v2)) + if (QAbstractItemModelPrivate::canConvertToDouble(v1) && QAbstractItemModelPrivate::canConvertToDouble(v2)) return v1.toDouble() < v2.toDouble(); return v1.toString() < v2.toString(); } diff --git a/src/gui/itemviews/qtreewidget_p.h b/src/gui/itemviews/qtreewidget_p.h index 96f734d..a089cf5 100644 --- a/src/gui/itemviews/qtreewidget_p.h +++ b/src/gui/itemviews/qtreewidget_p.h @@ -116,7 +116,6 @@ public: const QPair &right); static bool itemGreaterThan(const QPair &left, const QPair &right); - static bool canConvertToDouble(const QVariant &value); static QList::iterator sortedInsertionIterator( const QList::iterator &begin, const QList::iterator &end, -- cgit v0.12 From 3e2ee19553c2423e1e76264f3c3eb088cd31747a Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Tue, 9 Jun 2009 23:52:27 +0300 Subject: Made QListWidgetItem::operator<() check if the data is numerical when comparing. Merge-request: 631 Reviewed-by: Olivier Goffart --- src/gui/itemviews/qlistwidget.cpp | 5 +++- tests/auto/qlistwidget/tst_qlistwidget.cpp | 39 +++++++++++++++++++++--------- 2 files changed, 31 insertions(+), 13 deletions(-) diff --git a/src/gui/itemviews/qlistwidget.cpp b/src/gui/itemviews/qlistwidget.cpp index e1e509d..504908f 100644 --- a/src/gui/itemviews/qlistwidget.cpp +++ b/src/gui/itemviews/qlistwidget.cpp @@ -687,7 +687,10 @@ QVariant QListWidgetItem::data(int role) const */ bool QListWidgetItem::operator<(const QListWidgetItem &other) const { - return text() < other.text(); + const QVariant v1 = data(Qt::DisplayRole), v2 = other.data(Qt::DisplayRole); + if (QAbstractItemModelPrivate::canConvertToDouble(v1) && QAbstractItemModelPrivate::canConvertToDouble(v2)) + return v1.toDouble() < v2.toDouble(); + return v1.toString() < v2.toString(); } #ifndef QT_NO_DATASTREAM diff --git a/tests/auto/qlistwidget/tst_qlistwidget.cpp b/tests/auto/qlistwidget/tst_qlistwidget.cpp index 8d15aa4..8468cf3 100644 --- a/tests/auto/qlistwidget/tst_qlistwidget.cpp +++ b/tests/auto/qlistwidget/tst_qlistwidget.cpp @@ -883,31 +883,46 @@ void tst_QListWidget::itemStreaming() void tst_QListWidget::sortItems_data() { QTest::addColumn("order"); - QTest::addColumn("initialList"); - QTest::addColumn("expectedList"); + QTest::addColumn("initialList"); + QTest::addColumn("expectedList"); QTest::addColumn("expectedRows"); - QTest::newRow("ascending order") + QTest::newRow("ascending strings") << static_cast(Qt::AscendingOrder) - << (QStringList() << "c" << "d" << "a" << "b") - << (QStringList() << "a" << "b" << "c" << "d") + << (QVariantList() << QString("c") << QString("d") << QString("a") << QString("b")) + << (QVariantList() << QString("a") << QString("b") << QString("c") << QString("d")) << (IntList() << 2 << 3 << 0 << 1); - QTest::newRow("descending order") + QTest::newRow("descending strings") << static_cast(Qt::DescendingOrder) - << (QStringList() << "c" << "d" << "a" << "b") - << (QStringList() << "d" << "c" << "b" << "a") + << (QVariantList() << QString("c") << QString("d") << QString("a") << QString("b")) + << (QVariantList() << QString("d") << QString("c") << QString("b") << QString("a")) << (IntList() << 1 << 0 << 3 << 2); + + QTest::newRow("ascending numbers") + << static_cast(Qt::AscendingOrder) + << (QVariantList() << 1 << 11 << 2 << 22) + << (QVariantList() << 1 << 2 << 11 << 22) + << (IntList() << 0 << 2 << 1 << 3); + + QTest::newRow("descending numbers") + << static_cast(Qt::DescendingOrder) + << (QVariantList() << 1 << 11 << 2 << 22) + << (QVariantList() << 22 << 11 << 2 << 1) + << (IntList() << 3 << 1 << 2 << 0); } void tst_QListWidget::sortItems() { QFETCH(int, order); - QFETCH(QStringList, initialList); - QFETCH(QStringList, expectedList); + QFETCH(QVariantList, initialList); + QFETCH(QVariantList, expectedList); QFETCH(IntList, expectedRows); - testWidget->addItems(initialList); + foreach (const QVariant &data, initialList) { + QListWidgetItem *item = new QListWidgetItem(testWidget); + item->setData(Qt::DisplayRole, data); + } QAbstractItemModel *model = testWidget->model(); QList persistent; @@ -918,7 +933,7 @@ void tst_QListWidget::sortItems() QCOMPARE(testWidget->count(), expectedList.count()); for (int i = 0; i < testWidget->count(); ++i) - QCOMPARE(testWidget->item(i)->text(), expectedList.at(i)); + QCOMPARE(testWidget->item(i)->text(), expectedList.at(i).toString()); for (int k = 0; k < testWidget->count(); ++k) QCOMPARE(persistent.at(k).row(), expectedRows.at(k)); -- cgit v0.12 From 188a4ab62c99dcb113cad1833a0701d84a886e65 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Wed, 10 Jun 2009 15:35:45 +0200 Subject: Internal documentation for QAbstractItemModelPrivate::canConvertToDouble Also add QMetaType types as list or recognized numerical types Reviewed-by: thierry --- src/corelib/kernel/qabstractitemmodel.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/corelib/kernel/qabstractitemmodel.cpp b/src/corelib/kernel/qabstractitemmodel.cpp index 0a84ddb..6d6caf5 100644 --- a/src/corelib/kernel/qabstractitemmodel.cpp +++ b/src/corelib/kernel/qabstractitemmodel.cpp @@ -467,9 +467,17 @@ QAbstractItemModel *QAbstractItemModelPrivate::staticEmptyModel() return qEmptyModel(); } +/*! + \internal + return true if \a value contains a numerical type + + This function is used by our Q{Tree,Widget,Table}WidgetModel classes to sort. + We cannot rely on QVariant::canConvert because this would take strings as double + and then not sort strings correctly +*/ bool QAbstractItemModelPrivate::canConvertToDouble(const QVariant &value) { - switch (value.type()) { + switch (value.userType()) { case QVariant::Bool: case QVariant::Int: case QVariant::UInt: @@ -477,6 +485,12 @@ bool QAbstractItemModelPrivate::canConvertToDouble(const QVariant &value) case QVariant::ULongLong: case QVariant::Double: case QVariant::Char: + case QMetaType::Float: + case QMetaType::Short: + case QMetaType::UShort: + case QMetaType::UChar: + case QMetaType::ULong: + case QMetaType::Long: return true; default: return false; -- cgit v0.12 From 32f32ee3e752a6cc03505ddaa48d2849eaedc2a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Nilsen?= Date: Wed, 10 Jun 2009 14:31:20 +0200 Subject: QPainter::worldTransform() does not return identity matrix. QPainter::worldTransform() does not return identity matrix when created on a redirected widget. It should always be identity by default, and should only change as a result of QPainter::setWorldTransform. The reason it didn't return identity for redirected widgets, was that we translated the shared painter's world matrix directly. Since we cannot modify the world matrix directly, we have to store the shared painter's current world transform in a separate matrix (redirectedMatrix), reset the world transform to identity, and later combine the redirectedMatrix with world transforms set on the painter. Note that redirection_offset was in negative coordinates before, and that redirectionMatrix now is in positive coordinates, hence opposite signs around. Auto-test included. Reviewed-by: lars Reviewed-by: Samuel --- src/gui/painting/qpaintengineex.cpp | 3 +- src/gui/painting/qpainter.cpp | 47 ++++++++----------- src/gui/painting/qpainter_p.h | 2 +- tests/auto/qwidget/tst_qwidget.cpp | 94 +++++++++++++++++++++++++++++++++++++ 4 files changed, 115 insertions(+), 31 deletions(-) diff --git a/src/gui/painting/qpaintengineex.cpp b/src/gui/painting/qpaintengineex.cpp index 3cf5ff9..d2671c8 100644 --- a/src/gui/painting/qpaintengineex.cpp +++ b/src/gui/painting/qpaintengineex.cpp @@ -151,8 +151,7 @@ void QPaintEngineExPrivate::replayClipOperations() QTransform transform = q->state()->matrix; - QTransform redirection; - redirection.translate(-q->state()->redirection_offset.x(), -q->state()->redirection_offset.y()); + const QTransform &redirection = q->state()->redirectionMatrix; for (int i = 0; i < clipInfo.size(); ++i) { const QPainterClipInfo &info = clipInfo.at(i); diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index 4744f14..0ece498 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -281,10 +281,14 @@ bool QPainterPrivate::attachPainterPrivate(QPainter *q, QPaintDevice *pdev) q->d_ptr->state->wh = q->d_ptr->state->vh = widget->height(); // Update matrix. - if (q->d_ptr->state->WxF) - q->d_ptr->state->worldMatrix.translate(-offset.x(), -offset.y()); - else - q->d_ptr->state->redirection_offset = offset; + if (q->d_ptr->state->WxF) { + q->d_ptr->state->redirectionMatrix *= q->d_ptr->state->worldMatrix; + q->d_ptr->state->redirectionMatrix.translate(-offset.x(), -offset.y()); + q->d_ptr->state->worldMatrix = QTransform(); + q->d_ptr->state->WxF = false; + } else { + q->d_ptr->state->redirectionMatrix = QTransform::fromTranslate(-offset.x(), -offset.y()); + } q->d_ptr->updateMatrix(); QPaintEnginePrivate *enginePrivate = q->d_ptr->engine->d_func(); @@ -410,7 +414,7 @@ void QPainterPrivate::draw_helper(const QPainterPath &originalPath, DrawOperatio bool old_txinv = txinv; QTransform old_invMatrix = invMatrix; txinv = true; - invMatrix = QTransform().translate(-state->redirection_offset.x(), -state->redirection_offset.y()); + invMatrix = state->redirectionMatrix; QPainterPath clipPath = q->clipPath(); QRectF r = clipPath.boundingRect().intersected(absPathRect); absPathRect = r.toAlignedRect(); @@ -634,20 +638,7 @@ void QPainterPrivate::updateMatrix() state->matrix *= viewTransform(); txinv = false; // no inverted matrix - if (!state->redirection_offset.isNull()) { - // We want to translate in dev space so we do the adding of the redirection - // offset manually. - if (state->matrix.isAffine()) { - state->matrix = QTransform(state->matrix.m11(), state->matrix.m12(), - state->matrix.m21(), state->matrix.m22(), - state->matrix.dx()-state->redirection_offset.x(), - state->matrix.dy()-state->redirection_offset.y()); - } else { - QTransform temp; - temp.translate(-state->redirection_offset.x(), -state->redirection_offset.y()); - state->matrix *= temp; - } - } + state->matrix *= state->redirectionMatrix; if (extended) extended->transformChanged(); else @@ -1572,10 +1563,8 @@ void QPainter::restore() // replay the list of clip states, for (int i=0; istate->clipInfo.size(); ++i) { const QPainterClipInfo &info = d->state->clipInfo.at(i); - tmp->matrix.setMatrix(info.matrix.m11(), info.matrix.m12(), info.matrix.m13(), - info.matrix.m21(), info.matrix.m22(), info.matrix.m23(), - info.matrix.dx() - d->state->redirection_offset.x(), - info.matrix.dy() - d->state->redirection_offset.y(), info.matrix.m33()); + tmp->matrix = info.matrix; + tmp->matrix *= d->state->redirectionMatrix; tmp->clipOperation = info.operation; if (info.clipType == QPainterClipInfo::RectClip) { tmp->dirtyFlags = QPaintEngine::DirtyClipRegion | QPaintEngine::DirtyTransform; @@ -1689,7 +1678,7 @@ bool QPainter::begin(QPaintDevice *pd) d->state->painter = this; d->states.push_back(d->state); - d->state->redirection_offset = redirectionOffset; + d->state->redirectionMatrix.translate(-redirectionOffset.x(), -redirectionOffset.y()); d->state->brushOrigin = QPointF(); if (!d->engine) { @@ -1723,7 +1712,8 @@ bool QPainter::begin(QPaintDevice *pd) // Adjust offset for alien widgets painting outside the paint event. if (!inPaintEvent && paintOutsidePaintEvent && !widget->internalWinId() && widget->testAttribute(Qt::WA_WState_Created)) { - d->state->redirection_offset -= widget->mapTo(widget->nativeParentWidget(), QPoint()); + const QPoint offset = widget->mapTo(widget->nativeParentWidget(), QPoint()); + d->state->redirectionMatrix.translate(offset.x(), offset.y()); } break; } @@ -1805,11 +1795,12 @@ bool QPainter::begin(QPaintDevice *pd) d->state->wh = d->state->vh = pd->metric(QPaintDevice::PdmHeight); } - d->state->redirection_offset += d->engine->coordinateOffset(); + const QPoint coordinateOffset = d->engine->coordinateOffset(); + d->state->redirectionMatrix.translate(-coordinateOffset.x(), -coordinateOffset.y()); Q_ASSERT(d->engine->isActive()); - if (!d->state->redirection_offset.isNull()) + if (!d->state->redirectionMatrix.isIdentity()) d->updateMatrix(); Q_ASSERT(d->engine->isActive()); @@ -7704,7 +7695,7 @@ QPainterState::QPainterState(const QPainterState *s) clipRegion(s->clipRegion), clipPath(s->clipPath), clipOperation(s->clipOperation), renderHints(s->renderHints), clipInfo(s->clipInfo), - worldMatrix(s->worldMatrix), matrix(s->matrix), redirection_offset(s->redirection_offset), + worldMatrix(s->worldMatrix), matrix(s->matrix), redirectionMatrix(s->redirectionMatrix), wx(s->wx), wy(s->wy), ww(s->ww), wh(s->wh), vx(s->vx), vy(s->vy), vw(s->vw), vh(s->vh), opacity(s->opacity), WxF(s->WxF), VxF(s->VxF), diff --git a/src/gui/painting/qpainter_p.h b/src/gui/painting/qpainter_p.h index 6c8821a..8d4e6c5 100644 --- a/src/gui/painting/qpainter_p.h +++ b/src/gui/painting/qpainter_p.h @@ -158,7 +158,7 @@ public: QList clipInfo; // ### Make me smaller and faster to copy around... QTransform worldMatrix; // World transformation matrix, not window and viewport QTransform matrix; // Complete transformation matrix, - QPoint redirection_offset; + QTransform redirectionMatrix; int wx, wy, ww, wh; // window rectangle int vx, vy, vw, vh; // viewport rectangle qreal opacity; diff --git a/tests/auto/qwidget/tst_qwidget.cpp b/tests/auto/qwidget/tst_qwidget.cpp index 041aa7a..85d7de1 100644 --- a/tests/auto/qwidget/tst_qwidget.cpp +++ b/tests/auto/qwidget/tst_qwidget.cpp @@ -288,6 +288,7 @@ private slots: void render_systemClip3_data(); void render_systemClip3(); void render_task252837(); + void render_worldTransform(); void setContentsMargins(); @@ -7151,6 +7152,99 @@ void tst_QWidget::render_task252837() // Please do not crash. widget.render(&painter); } + +void tst_QWidget::render_worldTransform() +{ + class MyWidget : public QWidget + { public: + void paintEvent(QPaintEvent *) + { + QPainter painter(this); + // Make sure world transform is identity. + QCOMPARE(painter.worldTransform(), QTransform()); + + // Make sure device transform is correct. + const QPoint widgetOffset = geometry().topLeft(); + QTransform expectedDeviceTransform = QTransform::fromTranslate(105, 5); + expectedDeviceTransform.rotate(90); + expectedDeviceTransform.translate(widgetOffset.x(), widgetOffset.y()); + QCOMPARE(painter.deviceTransform(), expectedDeviceTransform); + + // Set new world transform. + QTransform newWorldTransform = QTransform::fromTranslate(10, 10); + newWorldTransform.rotate(90); + painter.setWorldTransform(newWorldTransform); + QCOMPARE(painter.worldTransform(), newWorldTransform); + + // Again, check device transform. + expectedDeviceTransform.translate(10, 10); + expectedDeviceTransform.rotate(90); + QCOMPARE(painter.deviceTransform(), expectedDeviceTransform); + + painter.fillRect(QRect(0, 0, 20, 10), Qt::green); + } + }; + + MyWidget widget; + widget.setFixedSize(100, 100); + widget.setPalette(Qt::red); + widget.setAutoFillBackground(true); + + MyWidget child; + child.setParent(&widget); + child.move(50, 50); + child.setFixedSize(50, 50); + child.setPalette(Qt::blue); + child.setAutoFillBackground(true); + + QImage image(QSize(110, 110), QImage::Format_RGB32); + image.fill(QColor(Qt::black).rgb()); + + QPainter painter(&image); + painter.translate(105, 5); + painter.rotate(90); + + const QTransform worldTransform = painter.worldTransform(); + const QTransform deviceTransform = painter.deviceTransform(); + + // Render widgets onto image. + widget.render(&painter); +#ifdef RENDER_DEBUG + image.save("render_worldTransform_image.png"); +#endif + + // Ensure the transforms are unchanged after render. + QCOMPARE(painter.worldTransform(), painter.worldTransform()); + QCOMPARE(painter.deviceTransform(), painter.deviceTransform()); + painter.end(); + + // Paint expected image. + QImage expected(QSize(110, 110), QImage::Format_RGB32); + expected.fill(QColor(Qt::black).rgb()); + + QPainter expectedPainter(&expected); + expectedPainter.translate(105, 5); + expectedPainter.rotate(90); + expectedPainter.save(); + expectedPainter.fillRect(widget.rect(),Qt::red); + expectedPainter.translate(10, 10); + expectedPainter.rotate(90); + expectedPainter.fillRect(QRect(0, 0, 20, 10), Qt::green); + expectedPainter.restore(); + expectedPainter.translate(50, 50); + expectedPainter.fillRect(child.rect(),Qt::blue); + expectedPainter.translate(10, 10); + expectedPainter.rotate(90); + expectedPainter.fillRect(QRect(0, 0, 20, 10), Qt::green); + expectedPainter.end(); + +#ifdef RENDER_DEBUG + expected.save("render_worldTransform_expected.png"); +#endif + + QCOMPARE(image, expected); +} + void tst_QWidget::setContentsMargins() { QLabel label("why does it always rain on me?"); -- cgit v0.12