From 17cda5c55273813cbedcced3a511f1c222978182 Mon Sep 17 00:00:00 2001 From: Gunnar Sletta Date: Mon, 2 Nov 2009 10:51:08 +0100 Subject: Check for null pixmap Reviewed-by: Trond --- src/gui/painting/qwindowsurface_x11.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/gui/painting/qwindowsurface_x11.cpp b/src/gui/painting/qwindowsurface_x11.cpp index 46c4c42..77e019c 100644 --- a/src/gui/painting/qwindowsurface_x11.cpp +++ b/src/gui/painting/qwindowsurface_x11.cpp @@ -94,6 +94,8 @@ QPaintDevice *QX11WindowSurface::paintDevice() void QX11WindowSurface::beginPaint(const QRegion &rgn) { #ifndef QT_NO_XRENDER + Q_ASSERT(!d_ptr->device.isNull()); + if (d_ptr->translucentBackground) { if (d_ptr->device.depth() != 32) static_cast(d_ptr->device.data_ptr().data())->convertToARGB32(); @@ -157,8 +159,8 @@ void QX11WindowSurface::setGeometry(const QRect &rect) QPixmap::x11SetDefaultScreen(d_ptr->widget->x11Info().screen()); QX11PixmapData *oldData = static_cast(d_ptr->device.pixmapData()); - Q_ASSERT(oldData); - if (!(oldData->flags & QX11PixmapData::Uninitialized) && hasStaticContents()) { + + if (oldData && !(oldData->flags & QX11PixmapData::Uninitialized) && hasStaticContents()) { // Copy the content of the old pixmap into the new one. QX11PixmapData *newData = new QX11PixmapData(QPixmapData::PixmapType); newData->resize(size.width(), size.height()); -- cgit v0.12 From 85e41590732f15cec16909bf1121d944ae684373 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Fri, 30 Oct 2009 13:37:05 +0100 Subject: Optimized graphics effects to not needlessly invalidate cache. When the effect rect changes we only need to invalidate the cache if the mode is ExpandToEffectRectPadMode. Reviewed-by: Gunnar Sletta --- src/gui/effects/qgraphicseffect.cpp | 9 ++++++++- src/gui/effects/qgraphicseffect_p.h | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/gui/effects/qgraphicseffect.cpp b/src/gui/effects/qgraphicseffect.cpp index 3a6bab5..c8e39da 100644 --- a/src/gui/effects/qgraphicseffect.cpp +++ b/src/gui/effects/qgraphicseffect.cpp @@ -279,6 +279,13 @@ QPixmap QGraphicsEffectSource::pixmap(Qt::CoordinateSystem system, QPoint *offse return pm; } +void QGraphicsEffectSourcePrivate::invalidateCache(bool effectRectChanged) const +{ + if (effectRectChanged && m_cachedMode != QGraphicsEffectSource::ExpandToEffectRectPadMode) + return; + QPixmapCache::remove(m_cacheKey); +} + /*! Constructs a new QGraphicsEffect instance having the specified \a parent. @@ -418,7 +425,7 @@ void QGraphicsEffect::updateBoundingRect() Q_D(QGraphicsEffect); if (d->source) { d->source->d_func()->effectBoundingRectChanged(); - d->source->d_func()->invalidateCache(); + d->source->d_func()->invalidateCache(true); } } diff --git a/src/gui/effects/qgraphicseffect_p.h b/src/gui/effects/qgraphicseffect_p.h index 1ed7103..0ff5794 100644 --- a/src/gui/effects/qgraphicseffect_p.h +++ b/src/gui/effects/qgraphicseffect_p.h @@ -85,7 +85,7 @@ public: virtual QPixmap pixmap(Qt::CoordinateSystem system, QPoint *offset = 0, QGraphicsEffectSource::PixmapPadMode mode = QGraphicsEffectSource::ExpandToTransparentBorderPadMode) const = 0; virtual void effectBoundingRectChanged() = 0; - void invalidateCache() const { QPixmapCache::remove(m_cacheKey); } + void invalidateCache(bool effectRectChanged = false) const; friend class QGraphicsScenePrivate; friend class QGraphicsItem; -- cgit v0.12 From 70b7f26c3155e83d59cae7b89ed1af3b57797a73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Fri, 30 Oct 2009 13:59:41 +0100 Subject: Added strict size parameter to QGLFramebufferObject pool. The strict size parameter can be used when it's critical that we get the exact size we ask for. Reviewed-by: Gunnar Sletta --- src/opengl/qpixmapdata_gl.cpp | 19 ++++++++++++++++--- src/opengl/qpixmapdata_gl_p.h | 2 +- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/opengl/qpixmapdata_gl.cpp b/src/opengl/qpixmapdata_gl.cpp index c965947..5ca37ef 100644 --- a/src/opengl/qpixmapdata_gl.cpp +++ b/src/opengl/qpixmapdata_gl.cpp @@ -89,13 +89,22 @@ static inline QSize maybeRoundToNextPowerOfTwo(const QSize &sz) } -QGLFramebufferObject *QGLFramebufferObjectPool::acquire(const QSize &requestSize, const QGLFramebufferObjectFormat &requestFormat) +QGLFramebufferObject *QGLFramebufferObjectPool::acquire(const QSize &requestSize, const QGLFramebufferObjectFormat &requestFormat, bool strictSize) { QGLFramebufferObject *chosen = 0; QGLFramebufferObject *candidate = 0; for (int i = 0; !chosen && i < m_fbos.size(); ++i) { QGLFramebufferObject *fbo = m_fbos.at(i); + if (strictSize) { + if (fbo->size() == requestSize && fbo->format() == requestFormat) { + chosen = fbo; + break; + } else { + continue; + } + } + if (fbo->format() == requestFormat) { // choose the fbo with a matching format and the closest size if (!candidate || areaDiff(requestSize, candidate) > areaDiff(requestSize, fbo)) @@ -127,7 +136,10 @@ QGLFramebufferObject *QGLFramebufferObjectPool::acquire(const QSize &requestSize } if (!chosen) { - chosen = new QGLFramebufferObject(maybeRoundToNextPowerOfTwo(requestSize), requestFormat); + if (strictSize) + chosen = new QGLFramebufferObject(requestSize, requestFormat); + else + chosen = new QGLFramebufferObject(maybeRoundToNextPowerOfTwo(requestSize), requestFormat); } if (!chosen->isValid()) { @@ -140,7 +152,8 @@ QGLFramebufferObject *QGLFramebufferObjectPool::acquire(const QSize &requestSize void QGLFramebufferObjectPool::release(QGLFramebufferObject *fbo) { - m_fbos << fbo; + if (fbo) + m_fbos << fbo; } diff --git a/src/opengl/qpixmapdata_gl_p.h b/src/opengl/qpixmapdata_gl_p.h index 6190d38..8a13e03 100644 --- a/src/opengl/qpixmapdata_gl_p.h +++ b/src/opengl/qpixmapdata_gl_p.h @@ -69,7 +69,7 @@ class QGLPixmapData; class QGLFramebufferObjectPool { public: - QGLFramebufferObject *acquire(const QSize &size, const QGLFramebufferObjectFormat &format); + QGLFramebufferObject *acquire(const QSize &size, const QGLFramebufferObjectFormat &format, bool strictSize = false); void release(QGLFramebufferObject *fbo); private: -- cgit v0.12 From 2a902676b74d0aa3482e722602879f7a02be1103 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Fri, 30 Oct 2009 14:26:55 +0100 Subject: Moved Qt::RenderHint back into QGraphicsBlurEffect and added a hint. Added AnimationHint, which didn't make too much sense in a generic enum, so Qt::RenderHint was moved back into QGraphicsBlurEffect as QGraphicsBlurEffect::BlurHint. Reviewed-by: Gunnar Sletta --- dist/changes-4.6.0 | 4 ++++ src/corelib/global/qnamespace.h | 5 ----- src/corelib/global/qnamespace.qdoc | 15 --------------- src/gui/effects/qgraphicseffect.cpp | 37 ++++++++++++++++++++++++++++--------- src/gui/effects/qgraphicseffect.h | 14 ++++++++++---- src/gui/image/qpixmapfilter.cpp | 18 ++++++++++++------ src/gui/image/qpixmapfilter_p.h | 5 +++-- src/opengl/qglpixmapfilter.cpp | 28 ++++++++++++++-------------- 8 files changed, 71 insertions(+), 55 deletions(-) diff --git a/dist/changes-4.6.0 b/dist/changes-4.6.0 index 7f723da..c7f9ad7 100644 --- a/dist/changes-4.6.0 +++ b/dist/changes-4.6.0 @@ -30,6 +30,10 @@ information about a particular change. * [245219] Added QXmlQuery::setFocus(const QString &focus); + - QGraphicsBlurEffect + * Since the 4.6 beta Qt::RenderHint has been moved to + QGraphicsBlurEffect::BlurHint. + - QVariant * Many optimisations * Added QVariant::toFloat() and QVariant::toReal() diff --git a/src/corelib/global/qnamespace.h b/src/corelib/global/qnamespace.h index 2b62c6b..42dd3a2 100644 --- a/src/corelib/global/qnamespace.h +++ b/src/corelib/global/qnamespace.h @@ -1645,11 +1645,6 @@ public: NavigationModeCursorAuto, NavigationModeCursorForceVisible }; - - enum RenderHint { - QualityHint, - PerformanceHint - }; } #ifdef Q_MOC_RUN ; diff --git a/src/corelib/global/qnamespace.qdoc b/src/corelib/global/qnamespace.qdoc index 5f9d01d..e3e881d 100644 --- a/src/corelib/global/qnamespace.qdoc +++ b/src/corelib/global/qnamespace.qdoc @@ -2873,18 +2873,3 @@ \sa QApplication::setNavigationMode() \sa QApplication::navigationMode() */ - -/*! - \enum Qt::RenderHint - \since 4.6 - - This enum describes the possible hints that can be used to control various - rendering operations. - - \value QualityHint Indicates that rendering quality is the most important factor, - at the potential cost of lower performance. - - \value PerformanceHint Indicates that rendering performance is the most important factor, - at the potential cost of lower quality. -*/ - diff --git a/src/gui/effects/qgraphicseffect.cpp b/src/gui/effects/qgraphicseffect.cpp index c8e39da..e181b18 100644 --- a/src/gui/effects/qgraphicseffect.cpp +++ b/src/gui/effects/qgraphicseffect.cpp @@ -613,6 +613,26 @@ void QGraphicsColorizeEffect::draw(QPainter *painter, QGraphicsEffectSource *sou */ /*! + \enum QGraphicsBlurEffect::BlurHint + \since 4.6 + + This enum describes the possible hints that can be used to control how + blur effects are applied. The hints might not have an effect in all the + paint engines. + + \value QualityHint Indicates that rendering quality is the most important factor, + at the potential cost of lower performance. + + \value PerformanceHint Indicates that rendering performance is the most important factor, + at the potential cost of lower quality. + + \value AnimationHint Indicates that the blur radius is going to be animated, hinting + that the implementation can keep a cache of blurred verisons of the source pixmap. + Do not use this hint if the source item is going to be dynamically changing. +*/ + + +/*! Constructs a new QGraphicsBlurEffect instance. The \a parent parameter is passed to QGraphicsEffect's constructor. */ @@ -620,7 +640,7 @@ QGraphicsBlurEffect::QGraphicsBlurEffect(QObject *parent) : QGraphicsEffect(*new QGraphicsBlurEffectPrivate, parent) { Q_D(QGraphicsBlurEffect); - d->filter->setBlurHint(Qt::PerformanceHint); + d->filter->setBlurHint(QGraphicsBlurEffect::PerformanceHint); } /*! @@ -667,20 +687,19 @@ void QGraphicsBlurEffect::setBlurRadius(qreal radius) \property QGraphicsBlurEffect::blurHint \brief the blur hint of the effect. - Use the Qt::PerformanceHint hint to say that you want a faster blur, - and the Qt::QualityHint hint to say that you prefer a higher quality blur. - - When animating the blur radius it's recommended to use Qt::PerformanceHint. + Use the PerformanceHint hint to say that you want a faster blur, + the QualityHint hint to say that you prefer a higher quality blur, + or the AnimationHint when you want to animate the blur radius. - By default, the blur hint is Qt::PerformanceHint. + By default, the blur hint is PerformanceHint. */ -Qt::RenderHint QGraphicsBlurEffect::blurHint() const +QGraphicsBlurEffect::BlurHint QGraphicsBlurEffect::blurHint() const { Q_D(const QGraphicsBlurEffect); return d->filter->blurHint(); } -void QGraphicsBlurEffect::setBlurHint(Qt::RenderHint hint) +void QGraphicsBlurEffect::setBlurHint(QGraphicsBlurEffect::BlurHint hint) { Q_D(QGraphicsBlurEffect); if (d->filter->blurHint() == hint) @@ -691,7 +710,7 @@ void QGraphicsBlurEffect::setBlurHint(Qt::RenderHint hint) } /*! - \fn void QGraphicsBlurEffect::blurHintChanged(Qt::RenderHint hint) + \fn void QGraphicsBlurEffect::blurHintChanged(Qt::BlurHint hint) This signal is emitted whenever the effect's blur hint changes. The \a hint parameter holds the effect's new blur hint. diff --git a/src/gui/effects/qgraphicseffect.h b/src/gui/effects/qgraphicseffect.h index bf18581..7335a25 100644 --- a/src/gui/effects/qgraphicseffect.h +++ b/src/gui/effects/qgraphicseffect.h @@ -183,22 +183,28 @@ class Q_GUI_EXPORT QGraphicsBlurEffect: public QGraphicsEffect { Q_OBJECT Q_PROPERTY(qreal blurRadius READ blurRadius WRITE setBlurRadius NOTIFY blurRadiusChanged) - Q_PROPERTY(Qt::RenderHint blurHint READ blurHint WRITE setBlurHint NOTIFY blurHintChanged) + Q_PROPERTY(BlurHint blurHint READ blurHint WRITE setBlurHint NOTIFY blurHintChanged) public: + enum BlurHint { + QualityHint, + PerformanceHint, + AnimationHint + }; + QGraphicsBlurEffect(QObject *parent = 0); ~QGraphicsBlurEffect(); QRectF boundingRectFor(const QRectF &rect) const; qreal blurRadius() const; - Qt::RenderHint blurHint() const; + BlurHint blurHint() const; public Q_SLOTS: void setBlurRadius(qreal blurRadius); - void setBlurHint(Qt::RenderHint hint); + void setBlurHint(BlurHint hint); Q_SIGNALS: void blurRadiusChanged(qreal blurRadius); - void blurHintChanged(Qt::RenderHint hint); + void blurHintChanged(BlurHint hint); protected: void draw(QPainter *painter, QGraphicsEffectSource *source); diff --git a/src/gui/image/qpixmapfilter.cpp b/src/gui/image/qpixmapfilter.cpp index d0de03e..e50cc8b 100644 --- a/src/gui/image/qpixmapfilter.cpp +++ b/src/gui/image/qpixmapfilter.cpp @@ -504,10 +504,10 @@ void QPixmapConvolutionFilter::draw(QPainter *painter, const QPointF &p, const Q class QPixmapBlurFilterPrivate : public QPixmapFilterPrivate { public: - QPixmapBlurFilterPrivate() : radius(5), hint(Qt::PerformanceHint) {} + QPixmapBlurFilterPrivate() : radius(5), hint(QGraphicsBlurEffect::PerformanceHint) {} qreal radius; - Qt::RenderHint hint; + QGraphicsBlurEffect::BlurHint hint; }; @@ -556,12 +556,18 @@ qreal QPixmapBlurFilter::radius() const Setting the blur hint to PerformanceHint causes the implementation to trade off visual quality to blur the image faster. Setting the blur hint to QualityHint causes the implementation to improve - visual quality at the expense of speed. The implementation is free - to ignore this value if it only has a single blur algorithm. + visual quality at the expense of speed. + + AnimationHint causes the implementation to optimize for animating + the blur radius, possibly by caching blurred versions of the source + pixmap. + + The implementation is free to ignore this value if it only has a single + blur algorithm. \internal */ -void QPixmapBlurFilter::setBlurHint(Qt::RenderHint hint) +void QPixmapBlurFilter::setBlurHint(QGraphicsBlurEffect::BlurHint hint) { Q_D(QPixmapBlurFilter); d->hint = hint; @@ -572,7 +578,7 @@ void QPixmapBlurFilter::setBlurHint(Qt::RenderHint hint) \internal */ -Qt::RenderHint QPixmapBlurFilter::blurHint() const +QGraphicsBlurEffect::BlurHint QPixmapBlurFilter::blurHint() const { Q_D(const QPixmapBlurFilter); return d->hint; diff --git a/src/gui/image/qpixmapfilter_p.h b/src/gui/image/qpixmapfilter_p.h index fc70795..6a96676 100644 --- a/src/gui/image/qpixmapfilter_p.h +++ b/src/gui/image/qpixmapfilter_p.h @@ -55,6 +55,7 @@ #include #include +#include QT_BEGIN_HEADER @@ -130,10 +131,10 @@ public: ~QPixmapBlurFilter(); void setRadius(qreal radius); - void setBlurHint(Qt::RenderHint hint); + void setBlurHint(QGraphicsBlurEffect::BlurHint hint); qreal radius() const; - Qt::RenderHint blurHint() const; + QGraphicsBlurEffect::BlurHint blurHint() const; QRectF boundingRectFor(const QRectF &rect) const; void draw(QPainter *painter, const QPointF &dest, const QPixmap &src, const QRectF &srcRect = QRectF()) const; diff --git a/src/opengl/qglpixmapfilter.cpp b/src/opengl/qglpixmapfilter.cpp index 2af69e0..3b94ad3 100644 --- a/src/opengl/qglpixmapfilter.cpp +++ b/src/opengl/qglpixmapfilter.cpp @@ -100,7 +100,7 @@ private: class QGLPixmapBlurFilter : public QGLCustomShaderStage, public QGLPixmapFilter { public: - QGLPixmapBlurFilter(Qt::RenderHint hint); + QGLPixmapBlurFilter(QGraphicsBlurEffect::BlurHint hint); void setUniforms(QGLShaderProgram *program); @@ -117,13 +117,13 @@ private: mutable bool m_haveCached; mutable int m_cachedRadius; - mutable Qt::RenderHint m_hint; + mutable QGraphicsBlurEffect::BlurHint m_hint; }; class QGLPixmapDropShadowFilter : public QGLCustomShaderStage, public QGLPixmapFilter { public: - QGLPixmapDropShadowFilter(Qt::RenderHint hint); + QGLPixmapDropShadowFilter(QGraphicsBlurEffect::BlurHint hint); void setUniforms(QGLShaderProgram *program); @@ -137,7 +137,7 @@ private: mutable bool m_haveCached; mutable int m_cachedRadius; - mutable Qt::RenderHint m_hint; + mutable QGraphicsBlurEffect::BlurHint m_hint; }; extern QGLWidget *qt_gl_share_widget(); @@ -153,13 +153,13 @@ QPixmapFilter *QGL2PaintEngineEx::pixmapFilter(int type, const QPixmapFilter *pr case QPixmapFilter::BlurFilter: { const QPixmapBlurFilter *proto = static_cast(prototype); - if (proto->blurHint() == Qt::PerformanceHint || proto->radius() <= 5) { + if (proto->blurHint() == QGraphicsBlurEffect::PerformanceHint || proto->radius() <= 5) { if (!d->fastBlurFilter) - d->fastBlurFilter.reset(new QGLPixmapBlurFilter(Qt::PerformanceHint)); + d->fastBlurFilter.reset(new QGLPixmapBlurFilter(QGraphicsBlurEffect::PerformanceHint)); return d->fastBlurFilter.data(); } if (!d->blurFilter) - d->blurFilter.reset(new QGLPixmapBlurFilter(Qt::QualityHint)); + d->blurFilter.reset(new QGLPixmapBlurFilter(QGraphicsBlurEffect::QualityHint)); return d->blurFilter.data(); } @@ -167,11 +167,11 @@ QPixmapFilter *QGL2PaintEngineEx::pixmapFilter(int type, const QPixmapFilter *pr const QPixmapDropShadowFilter *proto = static_cast(prototype); if (proto->blurRadius() <= 5) { if (!d->fastDropShadowFilter) - d->fastDropShadowFilter.reset(new QGLPixmapDropShadowFilter(Qt::PerformanceHint)); + d->fastDropShadowFilter.reset(new QGLPixmapDropShadowFilter(QGraphicsBlurEffect::PerformanceHint)); return d->fastDropShadowFilter.data(); } if (!d->dropShadowFilter) - d->dropShadowFilter.reset(new QGLPixmapDropShadowFilter(Qt::QualityHint)); + d->dropShadowFilter.reset(new QGLPixmapDropShadowFilter(QGraphicsBlurEffect::QualityHint)); return d->dropShadowFilter.data(); } @@ -327,7 +327,7 @@ static QByteArray qt_gl_convertToClamped(const QByteArray &source) return result; } -QGLPixmapBlurFilter::QGLPixmapBlurFilter(Qt::RenderHint hint) +QGLPixmapBlurFilter::QGLPixmapBlurFilter(QGraphicsBlurEffect::BlurHint hint) : m_haveCached(false) , m_cachedRadius(0) , m_hint(hint) @@ -341,7 +341,7 @@ bool QGLPixmapBlurFilter::processGL(QPainter *painter, const QPointF &pos, const int actualRadius = qRound(radius()); int filterRadius = actualRadius; int fastRadii[] = { 1, 2, 3, 5, 8, 15, 25 }; - if (m_hint == Qt::PerformanceHint) { + if (m_hint == QGraphicsBlurEffect::PerformanceHint) { uint i = 0; for (; i < (sizeof(fastRadii)/sizeof(*fastRadii))-1; ++i) { if (fastRadii[i+1] > filterRadius) @@ -428,7 +428,7 @@ void QGLPixmapBlurFilter::setUniforms(QGLShaderProgram *program) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - if (m_hint == Qt::QualityHint) { + if (m_hint == QGraphicsBlurEffect::QualityHint) { if (m_singlePass) program->setUniformValue("delta", 1.0 / m_textureSize.width(), 1.0 / m_textureSize.height()); else if (m_horizontalBlur) @@ -578,7 +578,7 @@ QByteArray QGLPixmapBlurFilter::generateGaussianShader(int radius, bool singlePa return source; } -QGLPixmapDropShadowFilter::QGLPixmapDropShadowFilter(Qt::RenderHint hint) +QGLPixmapDropShadowFilter::QGLPixmapDropShadowFilter(QGraphicsBlurEffect::BlurHint hint) : m_haveCached(false) , m_cachedRadius(0) , m_hint(hint) @@ -685,7 +685,7 @@ void QGLPixmapDropShadowFilter::setUniforms(QGLShaderProgram *program) alpha); } - if (m_hint == Qt::QualityHint) { + if (m_hint == QGraphicsBlurEffect::QualityHint) { if (m_singlePass) program->setUniformValue("delta", 1.0 / m_textureSize.width(), 1.0 / m_textureSize.height()); else if (m_horizontalBlur) -- cgit v0.12 From 64fbefa605d976ab752149bb39880893c82ad8c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Fri, 30 Oct 2009 14:00:35 +0100 Subject: Optimized animated blur radii in the GL 2 paint engine. We add an internal cache which keeps four half-scaled versions of the source pixmap at different blur radii, then we simply interpolate between the two pixmaps around the desired blur radius, or between the base source pixmap and the first blurred version. Reviewed-by: Gunnar Sletta --- .../gl2paintengineex/qpaintengineex_opengl2_p.h | 1 + src/opengl/qgl.h | 1 + src/opengl/qglpixmapfilter.cpp | 379 ++++++++++++++++++++- 3 files changed, 369 insertions(+), 12 deletions(-) diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h index 209cd36..4cf2a83 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h @@ -289,6 +289,7 @@ public: QScopedPointer convolutionFilter; QScopedPointer colorizeFilter; QScopedPointer blurFilter; + QScopedPointer animationBlurFilter; QScopedPointer fastBlurFilter; QScopedPointer dropShadowFilter; QScopedPointer fastDropShadowFilter; diff --git a/src/opengl/qgl.h b/src/opengl/qgl.h index e14e7fb..079953f 100644 --- a/src/opengl/qgl.h +++ b/src/opengl/qgl.h @@ -399,6 +399,7 @@ private: friend class QGLTextureGlyphCache; friend class QGLShareRegister; friend class QGLSharedResourceGuard; + friend class QGLPixmapBlurFilter; friend QGLFormat::OpenGLVersionFlags QGLFormat::openGLVersionFlags(); #ifdef Q_WS_MAC public: diff --git a/src/opengl/qglpixmapfilter.cpp b/src/opengl/qglpixmapfilter.cpp index 3b94ad3..ff19e06 100644 --- a/src/opengl/qglpixmapfilter.cpp +++ b/src/opengl/qglpixmapfilter.cpp @@ -43,6 +43,8 @@ #include "private/qpixmapdata_gl_p.h" #include "private/qpaintengineex_opengl2_p.h" #include "private/qglengineshadermanager_p.h" +#include "private/qpixmapdata_p.h" +#include "private/qimagepixmapcleanuphooks_p.h" #include "qglpixmapfilter_p.h" #include "qgraphicssystem_gl_p.h" #include "qpaintengine_opengl_p.h" @@ -54,7 +56,7 @@ #include "private/qapplication_p.h" #include "private/qmath_p.h" - +#include "qmath.h" QT_BEGIN_NAMESPACE @@ -114,6 +116,10 @@ private: mutable QSize m_textureSize; mutable bool m_horizontalBlur; mutable bool m_singlePass; + mutable bool m_animatedBlur; + + mutable qreal m_t; + mutable QSize m_targetSize; mutable bool m_haveCached; mutable int m_cachedRadius; @@ -153,6 +159,11 @@ QPixmapFilter *QGL2PaintEngineEx::pixmapFilter(int type, const QPixmapFilter *pr case QPixmapFilter::BlurFilter: { const QPixmapBlurFilter *proto = static_cast(prototype); + if (proto->blurHint() == QGraphicsBlurEffect::AnimationHint) { + if (!d->animationBlurFilter) + d->animationBlurFilter.reset(new QGLPixmapBlurFilter(proto->blurHint())); + return d->animationBlurFilter.data(); + } if (proto->blurHint() == QGraphicsBlurEffect::PerformanceHint || proto->radius() <= 5) { if (!d->fastBlurFilter) d->fastBlurFilter.reset(new QGLPixmapBlurFilter(QGraphicsBlurEffect::PerformanceHint)); @@ -328,20 +339,343 @@ static QByteArray qt_gl_convertToClamped(const QByteArray &source) } QGLPixmapBlurFilter::QGLPixmapBlurFilter(QGraphicsBlurEffect::BlurHint hint) - : m_haveCached(false) + : m_animatedBlur(false) + , m_haveCached(false) , m_cachedRadius(0) , m_hint(hint) { } +// should be even numbers as they will be divided by two +static const int qCachedBlurLevels[] = { 6, 14, 30 }; +static const int qNumCachedBlurTextures = sizeof(qCachedBlurLevels) / sizeof(*qCachedBlurLevels); +static const int qMaxCachedBlurLevel = qCachedBlurLevels[qNumCachedBlurTextures - 1]; + +static qreal qLogBlurLevel(int level) +{ + static bool initialized = false; + static qreal logBlurLevelCache[qNumCachedBlurTextures]; + if (!initialized) { + for (int i = 0; i < qNumCachedBlurTextures; ++i) + logBlurLevelCache[i] = qLn(qCachedBlurLevels[i]); + initialized = true; + } + return logBlurLevelCache[level]; +} + +class QGLBlurTextureInfo +{ +public: + QGLBlurTextureInfo(QSize size, GLuint textureIds[]) + : m_size(size) + { + for (int i = 0; i < qNumCachedBlurTextures; ++i) + m_textureIds[i] = textureIds[i]; + } + + ~QGLBlurTextureInfo() + { + glDeleteTextures(qNumCachedBlurTextures, m_textureIds); + } + + QSize size() const { return m_size; } + GLuint textureId(int i) const { return m_textureIds[i]; } + +private: + GLuint m_textureIds[qNumCachedBlurTextures]; + QSize m_size; +}; + +class QGLBlurTextureCache : public QObject +{ +public: + static QGLBlurTextureCache *cacheForContext(const QGLContext *context); + + QGLBlurTextureCache(); + ~QGLBlurTextureCache(); + + QGLBlurTextureInfo *takeBlurTextureInfo(const QPixmap &pixmap); + bool fitsInCache(const QPixmap &pixmap) const; + bool hasBlurTextureInfo(const QPixmap &pixmap) const; + void insertBlurTextureInfo(const QPixmap &pixmap, QGLBlurTextureInfo *info); + void clearBlurTextureInfo(const QPixmap &pixmap); + + void timerEvent(QTimerEvent *event); + +private: + static void pixmapDestroyed(QPixmap *pixmap); + + QCache cache; + + static QList blurTextureCaches; + + int timerId; +}; + +QList QGLBlurTextureCache::blurTextureCaches; + +static void QGLBlurTextureCache_free(void *ptr) +{ + delete reinterpret_cast(ptr); +} + +Q_GLOBAL_STATIC_WITH_ARGS(QGLContextResource, qt_blur_texture_caches, (QGLBlurTextureCache_free)) + +QGLBlurTextureCache::QGLBlurTextureCache() + : timerId(0) +{ + cache.setMaxCost(4 * 1024 * 1024); + blurTextureCaches.append(this); +} + +QGLBlurTextureCache::~QGLBlurTextureCache() +{ + blurTextureCaches.removeAt(blurTextureCaches.indexOf(this)); +} + +void QGLBlurTextureCache::timerEvent(QTimerEvent *event) +{ + killTimer(timerId); + timerId = 0; + + cache.clear(); +} + +QGLBlurTextureCache *QGLBlurTextureCache::cacheForContext(const QGLContext *context) +{ + QGLBlurTextureCache *p = reinterpret_cast(qt_blur_texture_caches()->value(context)); + if (!p) { + p = new QGLBlurTextureCache; + qt_blur_texture_caches()->insert(context, p); + } + return p; +} + +QGLBlurTextureInfo *QGLBlurTextureCache::takeBlurTextureInfo(const QPixmap &pixmap) +{ + return cache.take(pixmap.cacheKey()); +} + +void QGLBlurTextureCache::clearBlurTextureInfo(const QPixmap &pixmap) +{ + cache.remove(pixmap.cacheKey()); +} + +bool QGLBlurTextureCache::hasBlurTextureInfo(const QPixmap &pixmap) const +{ + return cache.contains(pixmap.cacheKey()); +} + +void QGLBlurTextureCache::insertBlurTextureInfo(const QPixmap &pixmap, QGLBlurTextureInfo *info) +{ + static bool hookAdded = false; + if (!hookAdded) { + QImagePixmapCleanupHooks::instance()->addPixmapDestructionHook(pixmapDestroyed); + hookAdded = true; + } + + QImagePixmapCleanupHooks::enableCleanupHooks(pixmap); + cache.insert(pixmap.cacheKey(), info, pixmap.width() * pixmap.height()); + + if (timerId) + killTimer(timerId); + + timerId = startTimer(1000); +} + +bool QGLBlurTextureCache::fitsInCache(const QPixmap &pixmap) const +{ + return pixmap.width() * pixmap.height() <= cache.maxCost(); +} + +void QGLBlurTextureCache::pixmapDestroyed(QPixmap *pixmap) +{ + foreach (QGLBlurTextureCache *cache, blurTextureCaches) { + if (cache->hasBlurTextureInfo(*pixmap)) + cache->clearBlurTextureInfo(*pixmap); + } +} + +static const char *qt_gl_interpolate_filter = + "uniform lowp float interpolationValue;" + "uniform lowp sampler2D interpolateTarget;" + "uniform highp vec4 interpolateMapping;" + "lowp vec4 customShader(lowp sampler2D src, highp vec2 srcCoords)" + "{" + " return mix(texture2D(interpolateTarget, interpolateMapping.xy + interpolateMapping.zw * srcCoords)," + " texture2D(src, srcCoords), interpolationValue);" + "}"; + +static void initializeTexture(GLuint id, int width, int height) +{ + glBindTexture(GL_TEXTURE_2D, id); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, + GL_RGBA, GL_UNSIGNED_BYTE, NULL); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glBindTexture(GL_TEXTURE_2D, 0); +} + bool QGLPixmapBlurFilter::processGL(QPainter *painter, const QPointF &pos, const QPixmap &src, const QRectF &) const { QGLPixmapBlurFilter *filter = const_cast(this); + QGLContext *ctx = const_cast(QGLContext::currentContext()); + QGLBlurTextureCache *blurTextureCache = QGLBlurTextureCache::cacheForContext(ctx); + + if (m_hint == QGraphicsBlurEffect::AnimationHint && blurTextureCache->fitsInCache(src)) { + QRect targetRect = src.rect().adjusted(-qMaxCachedBlurLevel, -qMaxCachedBlurLevel, qMaxCachedBlurLevel, qMaxCachedBlurLevel); + // ensure even dimensions (going to divide by two) + targetRect.setWidth((targetRect.width() + 1) & ~1); + targetRect.setHeight((targetRect.height() + 1) & ~1); + + QGLBlurTextureInfo *info = 0; + if (blurTextureCache->hasBlurTextureInfo(src)) { + info = blurTextureCache->takeBlurTextureInfo(src); + } else { + m_animatedBlur = false; + m_hint = QGraphicsBlurEffect::QualityHint; + m_singlePass = false; + + QGLFramebufferObjectFormat format; + format.setInternalTextureFormat(GL_RGBA); + QGLFramebufferObject *fbo = qgl_fbo_pool()->acquire(targetRect.size() / 2, format, true); + + if (!fbo) + return false; + + QPainter fboPainter(fbo); + QGL2PaintEngineEx *engine = static_cast(fboPainter.paintEngine()); + + glClearColor(0, 0, 0, 0); + glClear(GL_COLOR_BUFFER_BIT); + + // ensure GL_LINEAR filtering is used for scaling down to half the size + fboPainter.setRenderHint(QPainter::SmoothPixmapTransform); + fboPainter.setCompositionMode(QPainter::CompositionMode_Source); + fboPainter.drawPixmap(qMaxCachedBlurLevel / 2, qMaxCachedBlurLevel / 2, + targetRect.width() / 2 - qMaxCachedBlurLevel, targetRect.height() / 2 - qMaxCachedBlurLevel, src); + + GLuint textures[qNumCachedBlurTextures]; // blur textures + glGenTextures(qNumCachedBlurTextures, textures); + GLuint temp; // temp texture + glGenTextures(1, &temp); + + initializeTexture(temp, fbo->width(), fbo->height()); + m_textureSize = fbo->size(); + + int currentBlur = 0; + + QRect fboRect(0, 0, fbo->width(), fbo->height()); + GLuint sourceTexture = fbo->texture(); + for (int i = 0; i < qNumCachedBlurTextures; ++i) { + int targetBlur = qCachedBlurLevels[i] / 2; + + int blurDelta = qRound(qSqrt(targetBlur * targetBlur - currentBlur * currentBlur)); + QByteArray source = generateGaussianShader(blurDelta); + filter->setSource(source); + + currentBlur = targetBlur; + + // now we're going to be nasty and keep using the same FBO with different textures + glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, + GL_TEXTURE_2D, temp, 0); + + m_horizontalBlur = true; + filter->setOnPainter(&fboPainter); + engine->drawTexture(fboRect, sourceTexture, fbo->size(), fboRect); + filter->removeFromPainter(&fboPainter); + + sourceTexture = textures[i]; + initializeTexture(sourceTexture, fbo->width(), fbo->height()); + + glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, + GL_TEXTURE_2D, textures[i], 0); + + m_horizontalBlur = false; + filter->setOnPainter(&fboPainter); + engine->drawTexture(fboRect, temp, fbo->size(), fboRect); + filter->removeFromPainter(&fboPainter); + } + + glDeleteTextures(1, &temp); + + // reattach the original FBO texture + glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, + GL_TEXTURE_2D, fbo->texture(), 0); + + fboPainter.end(); + + qgl_fbo_pool()->release(fbo); + + info = new QGLBlurTextureInfo(fboRect.size(), textures); + } + + if (!m_haveCached || !m_animatedBlur) { + m_haveCached = true; + m_animatedBlur = true; + m_hint = QGraphicsBlurEffect::AnimationHint; + filter->setSource(qt_gl_interpolate_filter); + } + + QGL2PaintEngineEx *engine = static_cast(painter->paintEngine()); + painter->setRenderHint(QPainter::SmoothPixmapTransform); + filter->setOnPainter(painter); + + qreal logRadius = qLn(radius()); + + int t; + for (t = -1; t < qNumCachedBlurTextures - 2; ++t) { + if (logRadius < qLogBlurLevel(t+1)) + break; + } + + qreal logBase = t >= 0 ? qLogBlurLevel(t) : 0; + m_t = qBound(qreal(0), (logRadius - logBase) / (qLogBlurLevel(t+1) - logBase), qreal(1)); + + m_textureSize = info->size(); + + glActiveTexture(GL_TEXTURE0 + 3); + if (t >= 0) { + glBindTexture(GL_TEXTURE_2D, info->textureId(t)); + m_targetSize = info->size(); + } else { + QGLTexture *texture = + ctx->d_func()->bindTexture(src, GL_TEXTURE_2D, GL_RGBA, + QGLContext::InternalBindOption + | QGLContext::CanFlipNativePixmapBindOption); + m_targetSize = src.size(); + if (!(texture->options & QGLContext::InvertedYBindOption)) + m_targetSize.setHeight(-m_targetSize.height()); + } + + // restrict the target rect to the max of the radii we are interpolating between + int radiusDelta = qMaxCachedBlurLevel - qCachedBlurLevels[t+1]; + targetRect = targetRect.translated(pos.toPoint()).adjusted(radiusDelta, radiusDelta, -radiusDelta, -radiusDelta); + + radiusDelta /= 2; + QRect sourceRect = QRect(QPoint(), m_textureSize).adjusted(radiusDelta, radiusDelta, -radiusDelta, -radiusDelta); + + engine->drawTexture(targetRect, info->textureId(t+1), m_textureSize, sourceRect); + + glActiveTexture(GL_TEXTURE0 + 3); + glBindTexture(GL_TEXTURE_2D, 0); + + filter->removeFromPainter(painter); + blurTextureCache->insertBlurTextureInfo(src, info); + + return true; + } + + if (blurTextureCache->hasBlurTextureInfo(src)) + blurTextureCache->clearBlurTextureInfo(src); + int actualRadius = qRound(radius()); int filterRadius = actualRadius; int fastRadii[] = { 1, 2, 3, 5, 8, 15, 25 }; - if (m_hint == QGraphicsBlurEffect::PerformanceHint) { + if (m_hint != QGraphicsBlurEffect::QualityHint) { uint i = 0; for (; i < (sizeof(fastRadii)/sizeof(*fastRadii))-1; ++i) { if (fastRadii[i+1] > filterRadius) @@ -352,9 +686,10 @@ bool QGLPixmapBlurFilter::processGL(QPainter *painter, const QPointF &pos, const m_singlePass = filterRadius <= 3; - if (!m_haveCached || filterRadius != m_cachedRadius) { + if (!m_haveCached || m_animatedBlur || filterRadius != m_cachedRadius) { // Only regenerate the shader from source if parameters have changed. m_haveCached = true; + m_animatedBlur = false; m_cachedRadius = filterRadius; QByteArray source = generateGaussianShader(filterRadius, m_singlePass); filter->setSource(source); @@ -389,13 +724,12 @@ bool QGLPixmapBlurFilter::processGL(QPainter *painter, const QPointF &pos, const QPainter fboPainter(fbo); - if (src.hasAlphaChannel()) { - glClearColor(0, 0, 0, 0); - glClear(GL_COLOR_BUFFER_BIT); - } + glClearColor(0, 0, 0, 0); + glClear(GL_COLOR_BUFFER_BIT); // ensure GL_LINEAR filtering is used fboPainter.setRenderHint(QPainter::SmoothPixmapTransform); + fboPainter.setCompositionMode(QPainter::CompositionMode_Source); filter->setOnPainter(&fboPainter); QBrush pixmapBrush = src; pixmapBrush.setTransform(QTransform::fromTranslate(actualRadius, actualRadius)); @@ -428,6 +762,28 @@ void QGLPixmapBlurFilter::setUniforms(QGLShaderProgram *program) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + if (m_animatedBlur) { + program->setUniformValue("interpolateTarget", 3); + program->setUniformValue("interpolationValue", GLfloat(m_t)); + + if (m_textureSize == m_targetSize) { + program->setUniformValue("interpolateMapping", 0.0f, 0.0f, 1.0f, 1.0f); + } else { + float offsetX = (-qMaxCachedBlurLevel - 0.5) / qreal(m_targetSize.width()); + float offsetY = (-qMaxCachedBlurLevel - 0.5) / qreal(m_targetSize.height()); + + if (m_targetSize.height() < 0) + offsetY = 1 + offsetY; + + float scaleX = 2.0f * qreal(m_textureSize.width()) / qreal(m_targetSize.width()); + float scaleY = 2.0f * qreal(m_textureSize.height()) / qreal(m_targetSize.height()); + + program->setUniformValue("interpolateMapping", offsetX, offsetY, scaleX, scaleY); + } + + return; + } + if (m_hint == QGraphicsBlurEffect::QualityHint) { if (m_singlePass) program->setUniformValue("delta", 1.0 / m_textureSize.width(), 1.0 / m_textureSize.height()); @@ -632,13 +988,12 @@ bool QGLPixmapDropShadowFilter::processGL(QPainter *painter, const QPointF &pos, QPainter fboPainter(fbo); - if (src.hasAlphaChannel()) { - glClearColor(0, 0, 0, 0); - glClear(GL_COLOR_BUFFER_BIT); - } + glClearColor(0, 0, 0, 0); + glClear(GL_COLOR_BUFFER_BIT); // ensure GL_LINEAR filtering is used fboPainter.setRenderHint(QPainter::SmoothPixmapTransform); + fboPainter.setCompositionMode(QPainter::CompositionMode_Source); filter->setOnPainter(&fboPainter); QBrush pixmapBrush = src; pixmapBrush.setTransform(QTransform::fromTranslate(actualRadius, actualRadius)); -- cgit v0.12 From cb357aad0f26c36eb1f942ae37647f9de071c948 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Fri, 30 Oct 2009 19:28:43 +0100 Subject: Made QGraphicsEffectSource::draw() use cached pixmap if possible. Small optimization for the case where the source pixmap is cached. Reviewed-by: Gunnar Sletta --- src/gui/effects/qgraphicseffect.cpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/gui/effects/qgraphicseffect.cpp b/src/gui/effects/qgraphicseffect.cpp index e181b18..78a18d3 100644 --- a/src/gui/effects/qgraphicseffect.cpp +++ b/src/gui/effects/qgraphicseffect.cpp @@ -210,7 +210,23 @@ const QStyleOption *QGraphicsEffectSource::styleOption() const */ void QGraphicsEffectSource::draw(QPainter *painter) { - d_func()->draw(painter); + Q_D(const QGraphicsEffectSource); + + QPixmap pm; + if (QPixmapCache::find(d->m_cacheKey, &pm)) { + QTransform restoreTransform; + if (d->m_cachedSystem == Qt::DeviceCoordinates) { + restoreTransform = painter->worldTransform(); + painter->setWorldTransform(QTransform()); + } + + painter->drawPixmap(d->m_cachedOffset, pm); + + if (d->m_cachedSystem == Qt::DeviceCoordinates) + painter->setWorldTransform(restoreTransform); + } else { + d_func()->draw(painter); + } } /*! -- cgit v0.12 From 7f9c446f53ba89fb5add8ff6a62088eaa93d3460 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Mon, 2 Nov 2009 10:14:34 +0100 Subject: Fixed compiler warning on GCC about empty while statement. --- 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 3fec1f0..2a57468 100644 --- a/src/opengl/qgl.cpp +++ b/src/opengl/qgl.cpp @@ -2158,7 +2158,7 @@ QGLTexture* QGLContextPrivate::bindTexture(const QImage &image, GLenum target, G #ifndef QT_NO_DEBUG // Reset the gl error stack...git - while (glGetError() != GL_NO_ERROR); + while (glGetError() != GL_NO_ERROR) ; #endif // Scale the pixmap if needed. GL textures needs to have the -- cgit v0.12 From d4ea57ff9022305437fb371802b41120074d3467 Mon Sep 17 00:00:00 2001 From: Gunnar Sletta Date: Mon, 2 Nov 2009 13:56:40 +0100 Subject: Safeguard isNull() pixmaps in bindTexture and remove a compile warning Reviewed-by: TrustMe --- .../gl2paintengineex/qglengineshadermanager_p.h | 2 +- src/opengl/qgl.cpp | 39 ++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager_p.h b/src/opengl/gl2paintengineex/qglengineshadermanager_p.h index 59e50d0..50c1432 100644 --- a/src/opengl/gl2paintengineex/qglengineshadermanager_p.h +++ b/src/opengl/gl2paintengineex/qglengineshadermanager_p.h @@ -254,7 +254,7 @@ static const GLuint QT_VERTEX_COORDS_ATTR = 0; static const GLuint QT_TEXTURE_COORDS_ATTR = 1; static const GLuint QT_OPACITY_ATTR = 2; -struct QGLEngineShaderProg; +class QGLEngineShaderProg; class QGLEngineSharedShaders : public QObject { diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp index 3fec1f0..621d926 100644 --- a/src/opengl/qgl.cpp +++ b/src/opengl/qgl.cpp @@ -2445,6 +2445,9 @@ int QGLContextPrivate::maxTextureSize() */ GLuint QGLContext::bindTexture(const QImage &image, GLenum target, GLint format) { + if (image.isNull()) + return 0; + Q_D(QGLContext); QGLTexture *texture = d->bindTexture(image, target, format, false, DefaultBindOption); return texture->id; @@ -2477,6 +2480,9 @@ GLuint QGLContext::bindTexture(const QImage &image, GLenum target, GLint format) */ GLuint QGLContext::bindTexture(const QImage &image, GLenum target, GLint format, BindOptions options) { + if (image.isNull()) + return 0; + Q_D(QGLContext); QGLTexture *texture = d->bindTexture(image, target, format, false, options); return texture->id; @@ -2486,6 +2492,9 @@ GLuint QGLContext::bindTexture(const QImage &image, GLenum target, GLint format, /*! \internal */ GLuint QGLContext::bindTexture(const QImage &image, QMacCompatGLenum target, QMacCompatGLint format) { + if (image.isNull()) + return 0; + Q_D(QGLContext); QGLTexture *texture = d->bindTexture(image, GLenum(target), GLint(format), false, DefaultBindOption); return texture->id; @@ -2495,6 +2504,9 @@ GLuint QGLContext::bindTexture(const QImage &image, QMacCompatGLenum target, QMa GLuint QGLContext::bindTexture(const QImage &image, QMacCompatGLenum target, QMacCompatGLint format, BindOptions options) { + if (image.isNull()) + return 0; + Q_D(QGLContext); QGLTexture *texture = d->bindTexture(image, GLenum(target), GLint(format), false, options); return texture->id; @@ -2507,6 +2519,9 @@ GLuint QGLContext::bindTexture(const QImage &image, QMacCompatGLenum target, QMa */ GLuint QGLContext::bindTexture(const QPixmap &pixmap, GLenum target, GLint format) { + if (pixmap.isNull()) + return 0; + Q_D(QGLContext); QGLTexture *texture = d->bindTexture(pixmap, target, format, DefaultBindOption); return texture->id; @@ -2521,6 +2536,9 @@ GLuint QGLContext::bindTexture(const QPixmap &pixmap, GLenum target, GLint forma */ GLuint QGLContext::bindTexture(const QPixmap &pixmap, GLenum target, GLint format, BindOptions options) { + if (pixmap.isNull()) + return 0; + Q_D(QGLContext); QGLTexture *texture = d->bindTexture(pixmap, target, format, options); return texture->id; @@ -2530,6 +2548,9 @@ GLuint QGLContext::bindTexture(const QPixmap &pixmap, GLenum target, GLint forma /*! \internal */ GLuint QGLContext::bindTexture(const QPixmap &pixmap, QMacCompatGLenum target, QMacCompatGLint format) { + if (pixmap.isNull()) + return 0; + Q_D(QGLContext); QGLTexture *texture = d->bindTexture(pixmap, GLenum(target), GLint(format), DefaultBindOption); return texture->id; @@ -2538,6 +2559,9 @@ GLuint QGLContext::bindTexture(const QPixmap &pixmap, QMacCompatGLenum target, Q GLuint QGLContext::bindTexture(const QPixmap &pixmap, QMacCompatGLenum target, QMacCompatGLint format, BindOptions options) { + if (pixmap.isNull()) + return 0; + Q_D(QGLContext); QGLTexture *texture = d->bindTexture(pixmap, GLenum(target), GLint(format), options); return texture->id; @@ -4595,6 +4619,9 @@ bool QGLWidget::autoBufferSwap() const */ GLuint QGLWidget::bindTexture(const QImage &image, GLenum target, GLint format) { + if (image.isNull()) + return 0; + Q_D(QGLWidget); return d->glcx->bindTexture(image, target, format, QGLContext::DefaultBindOption); } @@ -4608,6 +4635,9 @@ GLuint QGLWidget::bindTexture(const QImage &image, GLenum target, GLint format) */ GLuint QGLWidget::bindTexture(const QImage &image, GLenum target, GLint format, QGLContext::BindOptions options) { + if (image.isNull()) + return 0; + Q_D(QGLWidget); return d->glcx->bindTexture(image, target, format, options); } @@ -4617,6 +4647,9 @@ GLuint QGLWidget::bindTexture(const QImage &image, GLenum target, GLint format, /*! \internal */ GLuint QGLWidget::bindTexture(const QImage &image, QMacCompatGLenum target, QMacCompatGLint format) { + if (image.isNull()) + return 0; + Q_D(QGLWidget); return d->glcx->bindTexture(image, GLenum(target), GLint(format), QGLContext::DefaultBindOption); } @@ -4624,6 +4657,9 @@ GLuint QGLWidget::bindTexture(const QImage &image, QMacCompatGLenum target, QMac GLuint QGLWidget::bindTexture(const QImage &image, QMacCompatGLenum target, QMacCompatGLint format, QGLContext::BindOptions options) { + if (image.isNull()) + return 0; + Q_D(QGLWidget); return d->glcx->bindTexture(image, GLenum(target), GLint(format), options); } @@ -4637,6 +4673,9 @@ GLuint QGLWidget::bindTexture(const QImage &image, QMacCompatGLenum target, QMac */ GLuint QGLWidget::bindTexture(const QPixmap &pixmap, GLenum target, GLint format) { + if (pixmap.isNull()) + return 0; + Q_D(QGLWidget); return d->glcx->bindTexture(pixmap, target, format, QGLContext::DefaultBindOption); } -- cgit v0.12 From 99bbe6fa6c2322449bb8ab7dda09c53b18cde68d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Mon, 2 Nov 2009 14:13:05 +0100 Subject: Minor doc fixes for QGLContext::BindOption. Reviewed-by: Gunnar Sletta --- src/opengl/qgl.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp index 2a57468..6370afd 100644 --- a/src/opengl/qgl.cpp +++ b/src/opengl/qgl.cpp @@ -1773,10 +1773,12 @@ Q_OPENGL_EXPORT QGLShareRegister* qgl_share_reg() /*! \enum QGLContext::BindOption + \since 4.6 + A set of options to decide how to bind a texture using bindTexture(). \value NoBindOption Don't do anything, pass the texture straight - thru. + through. \value InvertedYBindOption Specifies that the texture should be flipped over the X axis so that the texture coordinate 0,0 corresponds to -- cgit v0.12 From ab473d6a8e4fa619537c4cdaaf1b6a9d8544b30a Mon Sep 17 00:00:00 2001 From: Kim Motoyoshi Kalland Date: Mon, 2 Nov 2009 15:30:55 +0100 Subject: Fixed holes in thick strokes. When stroking small paths with a thick pen, it looked like the winding fill rule was ignored. The bug was in the stroke generator which generated paths where the winding number could incorrectly become zero. Task-number: QTBUG-1537 Reviewed-by: Gunnar --- src/gui/painting/qstroker.cpp | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/gui/painting/qstroker.cpp b/src/gui/painting/qstroker.cpp index c57b3c1..228a6b1 100644 --- a/src/gui/painting/qstroker.cpp +++ b/src/gui/painting/qstroker.cpp @@ -452,6 +452,17 @@ void QStroker::joinPoints(qfixed focal_x, qfixed focal_y, const QLineF &nextLine #endif if (join == FlatJoin) { + QLineF prevLine(qt_fixed_to_real(m_back2X), qt_fixed_to_real(m_back2Y), + qt_fixed_to_real(m_back1X), qt_fixed_to_real(m_back1Y)); + QPointF isect; + QLineF::IntersectType type = prevLine.intersect(nextLine, &isect); + QLineF shortCut(prevLine.p2(), nextLine.p1()); + qreal angle = shortCut.angleTo(prevLine); + if (type == QLineF::BoundedIntersection || (angle > 90 && !qFuzzyCompare(angle, (qreal)90))) { + emitLineTo(focal_x, focal_y); + emitLineTo(qt_real_to_fixed(nextLine.x1()), qt_real_to_fixed(nextLine.y1())); + return; + } emitLineTo(qt_real_to_fixed(nextLine.x1()), qt_real_to_fixed(nextLine.y1())); @@ -468,8 +479,8 @@ void QStroker::joinPoints(qfixed focal_x, qfixed focal_y, const QLineF &nextLine // If we are on the inside, do the short cut... QLineF shortCut(prevLine.p2(), nextLine.p1()); qreal angle = shortCut.angleTo(prevLine); - if (type == QLineF::BoundedIntersection || (angle > 90 && !qFuzzyCompare(angle, (qreal)90))) { + emitLineTo(focal_x, focal_y); emitLineTo(qt_real_to_fixed(nextLine.x1()), qt_real_to_fixed(nextLine.y1())); return; } @@ -509,8 +520,9 @@ void QStroker::joinPoints(qfixed focal_x, qfixed focal_y, const QLineF &nextLine qfixed offset = m_strokeWidth / 2; QLineF shortCut(prevLine.p2(), nextLine.p1()); - qreal angle = prevLine.angle(shortCut); + qreal angle = shortCut.angleTo(prevLine); if (type == QLineF::BoundedIntersection || (angle > 90 && !qFuzzyCompare(angle, (qreal)90))) { + emitLineTo(focal_x, focal_y); emitLineTo(qt_real_to_fixed(nextLine.x1()), qt_real_to_fixed(nextLine.y1())); return; } @@ -581,6 +593,13 @@ void QStroker::joinPoints(qfixed focal_x, qfixed focal_y, const QLineF &nextLine qt_real_to_fixed(l1.x1()), qt_real_to_fixed(l1.y1())); } else if (join == SvgMiterJoin) { + QLineF shortCut(prevLine.p2(), nextLine.p1()); + qreal angle = shortCut.angleTo(prevLine); + if (type == QLineF::BoundedIntersection || (angle > 90 && !qFuzzyCompare(angle, (qreal)90))) { + emitLineTo(focal_x, focal_y); + emitLineTo(qt_real_to_fixed(nextLine.x1()), qt_real_to_fixed(nextLine.y1())); + return; + } QLineF miterLine(QPointF(qt_fixed_to_real(focal_x), qt_fixed_to_real(focal_y)), isect); if (miterLine.length() > qt_fixed_to_real(m_strokeWidth * m_miterLimit) / 2) { -- cgit v0.12 From 243163c3f61c79146c37da0a4da4bacafa8e1321 Mon Sep 17 00:00:00 2001 From: Gunnar Sletta Date: Mon, 2 Nov 2009 16:06:06 +0100 Subject: Fixed test, QGraphicsSourceEffect::pixmap(), caching caused failure. Reviewed-by: Samuel --- src/gui/effects/qgraphicseffect.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/gui/effects/qgraphicseffect.cpp b/src/gui/effects/qgraphicseffect.cpp index 3a6bab5..f24d424 100644 --- a/src/gui/effects/qgraphicseffect.cpp +++ b/src/gui/effects/qgraphicseffect.cpp @@ -97,6 +97,8 @@ */ #include "qgraphicseffect_p.h" +#include "private/qgraphicsitem_p.h" + #include #include @@ -260,6 +262,12 @@ QPixmap QGraphicsEffectSource::pixmap(Qt::CoordinateSystem system, QPoint *offse return ((QGraphicsPixmapItem *) item)->pixmap(); } + if (system == Qt::DeviceCoordinates && item + && !static_cast(d_func())->info) { + qWarning("QGraphicsEffectSource::pixmap: Not yet implemented, lacking device context"); + return QPixmap(); + } + QPixmap pm; if (d->m_cachedSystem == system && d->m_cachedMode == mode) QPixmapCache::find(d->m_cacheKey, &pm); -- cgit v0.12 From 915f20bb167aa09ca8c8db478a2a78d5e357b67e Mon Sep 17 00:00:00 2001 From: Gunnar Sletta Date: Mon, 2 Nov 2009 16:58:56 +0100 Subject: Better cosmetic pen scaling for beziers in tristroker. Reviewed-By: Samuel --- src/opengl/gl2paintengineex/qtriangulatingstroker.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/opengl/gl2paintengineex/qtriangulatingstroker.cpp b/src/opengl/gl2paintengineex/qtriangulatingstroker.cpp index ad18a51..1163eba 100644 --- a/src/opengl/gl2paintengineex/qtriangulatingstroker.cpp +++ b/src/opengl/gl2paintengineex/qtriangulatingstroker.cpp @@ -114,7 +114,7 @@ void QTriangulatingStroker::process(const QVectorPath &path, const QPen &pen) if (m_join_style == Qt::RoundJoin) m_join_style = Qt::MiterJoin; m_curvyness_add = 0.5; - m_curvyness_mul = CURVE_FLATNESS; + m_curvyness_mul = CURVE_FLATNESS / m_inv_scale; m_roundness = 1; } else if (cosmetic) { m_curvyness_add = realWidth / 2; -- cgit v0.12 From b72d41cf30f82c74c10c31808907cc990c86efe6 Mon Sep 17 00:00:00 2001 From: Rhys Weatherley Date: Tue, 3 Nov 2009 08:23:18 +1000 Subject: Protect the OpenVG engine from null QPixmapData objects Reviewed-by: Sarah Smith --- src/openvg/qpaintengine_vg.cpp | 10 ++++++++++ src/openvg/qpixmapdata_vg.cpp | 2 ++ src/openvg/qpixmapfilter_vg.cpp | 12 ++++++++++++ 3 files changed, 24 insertions(+) diff --git a/src/openvg/qpaintengine_vg.cpp b/src/openvg/qpaintengine_vg.cpp index 8a485a0..047d9d8 100644 --- a/src/openvg/qpaintengine_vg.cpp +++ b/src/openvg/qpaintengine_vg.cpp @@ -1178,6 +1178,8 @@ VGPaintType QVGPaintEnginePrivate::setBrush case Qt::TexturePattern: { // The brush is a texture specified by a QPixmap/QImage. QPixmapData *pd = brush.texture().pixmapData(); + if (!pd) + break; // null QPixmap VGImage vgImg; bool deref = false; if (pd->pixelType() == QPixmapData::BitmapType) { @@ -2893,6 +2895,8 @@ void qt_vg_drawVGImageStencil void QVGPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr) { QPixmapData *pd = pm.pixmapData(); + if (!pd) + return; // null QPixmap if (pd->classId() == QPixmapData::OpenVGClass) { Q_D(QVGPaintEngine); QVGPixmapData *vgpd = static_cast(pd); @@ -2910,6 +2914,8 @@ void QVGPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF void QVGPaintEngine::drawPixmap(const QPointF &pos, const QPixmap &pm) { QPixmapData *pd = pm.pixmapData(); + if (!pd) + return; // null QPixmap if (pd->classId() == QPixmapData::OpenVGClass) { Q_D(QVGPaintEngine); QVGPixmapData *vgpd = static_cast(pd); @@ -2985,6 +2991,8 @@ void QVGPaintEngine::drawPixmaps // If the pixmap is not VG, or the transformation is projective, // then fall back to the default implementation. QPixmapData *pd = pixmap.pixmapData(); + if (!pd) + return; // null QPixmap if (pd->classId() != QPixmapData::OpenVGClass || !d->simpleTransform) { QPaintEngineEx::drawPixmaps(drawingData, dataCount, pixmap, hints); return; @@ -3581,6 +3589,8 @@ void QVGCompositionHelper::drawCursorPixmap // Fetch the VGImage from the pixmap if possible. QPixmapData *pd = pixmap.pixmapData(); + if (!pd) + return; // null QPixmap if (pd->classId() == QPixmapData::OpenVGClass) { QVGPixmapData *vgpd = static_cast(pd); if (vgpd->isValid()) diff --git a/src/openvg/qpixmapdata_vg.cpp b/src/openvg/qpixmapdata_vg.cpp index f86e116..3254aa3 100644 --- a/src/openvg/qpixmapdata_vg.cpp +++ b/src/openvg/qpixmapdata_vg.cpp @@ -369,6 +369,8 @@ QImage::Format QVGPixmapData::sourceFormat() const Q_OPENVG_EXPORT VGImage qPixmapToVGImage(const QPixmap& pixmap) { QPixmapData *pd = pixmap.pixmapData(); + if (!pd) + return VG_INVALID_HANDLE; // null QPixmap if (pd->classId() == QPixmapData::OpenVGClass) { QVGPixmapData *vgpd = static_cast(pd); if (vgpd->isValid()) diff --git a/src/openvg/qpixmapfilter_vg.cpp b/src/openvg/qpixmapfilter_vg.cpp index 8e104db..e17c728 100644 --- a/src/openvg/qpixmapfilter_vg.cpp +++ b/src/openvg/qpixmapfilter_vg.cpp @@ -65,6 +65,9 @@ void QVGPixmapConvolutionFilter::draw (QPainter *painter, const QPointF &dest, const QPixmap &src, const QRectF &srcRect) const { + if (src.isNull()) + return; + if (src.pixmapData()->classId() != QPixmapData::OpenVGClass) { // The pixmap data is not an instance of QVGPixmapData, so fall // back to the default convolution filter implementation. @@ -135,6 +138,9 @@ QVGPixmapColorizeFilter::~QVGPixmapColorizeFilter() void QVGPixmapColorizeFilter::draw(QPainter *painter, const QPointF &dest, const QPixmap &src, const QRectF &srcRect) const { + if (src.isNull()) + return; + if (src.pixmapData()->classId() != QPixmapData::OpenVGClass) { // The pixmap data is not an instance of QVGPixmapData, so fall // back to the default colorize filter implementation. @@ -225,6 +231,9 @@ QVGPixmapDropShadowFilter::~QVGPixmapDropShadowFilter() void QVGPixmapDropShadowFilter::draw(QPainter *painter, const QPointF &dest, const QPixmap &src, const QRectF &srcRect) const { + if (src.isNull()) + return; + if (src.pixmapData()->classId() != QPixmapData::OpenVGClass) { // The pixmap data is not an instance of QVGPixmapData, so fall // back to the default drop shadow filter implementation. @@ -290,6 +299,9 @@ QVGPixmapBlurFilter::~QVGPixmapBlurFilter() void QVGPixmapBlurFilter::draw(QPainter *painter, const QPointF &dest, const QPixmap &src, const QRectF &srcRect) const { + if (src.isNull()) + return; + if (src.pixmapData()->classId() != QPixmapData::OpenVGClass) { // The pixmap data is not an instance of QVGPixmapData, so fall // back to the default blur filter implementation. -- cgit v0.12 From 4eff66941486568cd25dc9aaa372f9d36b84dad8 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Tue, 3 Nov 2009 10:05:11 +0100 Subject: doc: Polish documentation for state machine framework Fix some examples and wording, and add some clarification based on comments in documentation review session. Reviewed-by: Kent Hansen --- doc/src/frameworks-technologies/statemachine.qdoc | 104 +++++++++++----------- doc/src/snippets/statemachine/main2.cpp | 11 +-- doc/src/snippets/statemachine/main5.cpp | 44 +++++++-- 3 files changed, 93 insertions(+), 66 deletions(-) diff --git a/doc/src/frameworks-technologies/statemachine.qdoc b/doc/src/frameworks-technologies/statemachine.qdoc index ed8bc85..ac10314 100644 --- a/doc/src/frameworks-technologies/statemachine.qdoc +++ b/doc/src/frameworks-technologies/statemachine.qdoc @@ -75,6 +75,11 @@ states can be configured to set properties and invoke methods on QObjects. Qt's event system is used to drive the state machines. + The state graph in the State Machine framework is hierarchical. States can be nested inside of + other states, and the current configuration of the state machine consists of the set of states + which are currently active. All the states in a valid configuration of the state machine will + have a common ancestor. + \section1 Classes in the State Machine Framework These classes are provided by qt for creating event-driven state machines. @@ -269,9 +274,17 @@ When a parallel state group is entered, all its child states will be simultaneously entered. Transitions within the individual child states - operate normally. However, any of the child states may take a transition - outside the parent state. When this happens, the parent state and all of its - child states are exited. + operate normally. However, any of the child states may take a transition which exits the parent + state. When this happens, the parent state and all of its child states are exited. + + The parallelism in the State Machine framework follows an interleaved semantics. All parallel + operations will be executed in a single, atomic step of the event processing, so no event can + interrupt the parallel operations. However, events will still be processed sequentially, since + the machine itself is single threaded. As an example: Consider the situation where there are two + transitions that exit the same parallel state group, and their conditions become true + simultaneously. In this case, the event that is processed last of the two will not have any + effect, since the first event will already have caused the machine to exit from the parallel + state. \section1 Detecting that a Composite State has Finished @@ -414,16 +427,7 @@ Take the following code: \code - QStateMachine machine; - machine.setGlobalRestorePolicy(QStateMachine::RestoreProperties); - - QState *s1 = new QState(); - s1->assignProperty(object, "fooBar", 1.0); - machine.addState(s1); - machine.setInitialState(s1); - - QState *s2 = new QState(); - machine.addState(s2); + \snippet doc/src/snippets/statemachine/main5.cpp 0 \endcode Lets say the property \c fooBar is 0.0 when the machine starts. When the machine is in state @@ -434,19 +438,7 @@ If we are using nested states, the parent defines a value for the property which is inherited by all descendants that do not explicitly assign a value to the property. \code - QStateMachine machine; - machine.setGlobalRestorePolicy(QStateMachine::RestoreProperties); - - QState *s1 = new QState(); - s1->assignProperty(object, "fooBar", 1.0); - machine.addState(s1); - machine.setInitialState(s1); - - QState *s2 = new QState(s1); - s2->assignProperty(object, "fooBar", 2.0); - s1->setInitialState(s2); - - QState *s3 = new QState(s1); + \snippet doc/src/snippets/statemachine/main5.cpp 2 \endcode Here \c s1 has two children: \c s2 and \c s3. When \c s2 is entered, the property \c fooBar @@ -461,13 +453,7 @@ Say we have the following code: \code - QState *s1 = new QState(); - QState *s2 = new QState(); - - s1->assignProperty(button, "geometry", QRectF(0, 0, 50, 50)); - s2->assignProperty(button, "geometry", QRectF(0, 0, 100, 100)); - - s1->addTransition(button, SIGNAL(clicked()), s2); + \snippet doc/src/snippets/statemachine/main5.cpp 3 \endcode Here we define two states of a user interface. In \c s1 the \c button is small, and in \c s2 @@ -477,14 +463,7 @@ object. \code - QState *s1 = new QState(); - QState *s2 = new QState(); - - s1->assignProperty(button, "geometry", QRectF(0, 0, 50, 50)); - s2->assignProperty(button, "geometry", QRectF(0, 0, 100, 100)); - - QSignalTransition *transition = s1->addTransition(button, SIGNAL(clicked()), s2); - transition->addAnimation(new QPropertyAnimation(button, "geometry")); + \snippet doc/src/snippets/statemachine/main5.cpp 4 \endcode Adding an animation for the property in question means that the property assignment will no @@ -504,28 +483,45 @@ property can potentially have any value, depending on the animation. In some cases, it can be useful to be able to detect when the property has actually been assigned - the value defined by a state. For this, we can use the state's polished() signal. + the value defined by a state. + + Say we have the following code: \code - QState *s1 = new QState(); - s1->assignProperty(button, "geometry", QRectF(0, 0, 50, 50)); + \snippet doc/src/snippets/statemachine/main5.cpp 5 + \endcode - QState *s2 = new QState(); + When \c button is clicked, the machine will transition into state \c s2, which will set the + geometry of the button, and then pop up a message box to alert the user that the geometry has + been changed. + + In the normal case, where animations are not used, this will operate as expected. However, if + an animation for the \c geometry of \c button is set on the transition between \c s1 and \c s2, + the animation will be started when \c s2 is entered, but the \c geometry property will not + actually reach its defined value before the animation is finished running. In this case, the + message box will pop up before the geometry of the button has actually been set. - s1->addTransition(s1, SIGNAL(polished()), s2); + To ensure that the message box does not pop up until the geometry actually reaches its final + value, we can use the state's polished() signal. The polished() signal will be emitted when the + the property is assigned its final value, whether this is done immediately or after the animation + has finished playing. + \code + \snippet doc/src/snippets/statemachine/main5.cpp 6 \endcode - The machine will be in state \c s1 until the \c geometry property has been set. Then it will - immediately transition into \c s2. If the transition into \c s1 has an animation for the \c - geometry property, then the machine will stay in \c s1 until the animation has finished. If there - is no animation, it will simply set the property and immediately enter state \c s2. + In this example, when \c button is clicked, the machine will enter \c s2. It will remain in state + \c s2 until the \c geometry property has been set to \c QRect(0, 0, 50, 50). Then it will + transition into \c s3. When \c s3 is entered, the message box will pop up. If the transition into + \c s2 has an animation for the \c geometry property, then the machine will stay in \c s2 until the + animation has finished playing. If there is no such animation, it will simply set the property and + immediately enter state \c s3. - Either way, when the machine is in state \c s2, the property \c geometry has been assigned the - defined value. + Either way, when the machine is in state \c s3, you are guaranteed that the property \c geometry + has been assigned the defined value. If the global restore policy is set to QStateMachine::RestoreProperties, the state will not emit the polished() signal until these have been executed as well. - \section1 What happens if a state is exited before the animation has finished + \section1 What Happens If A State Is Exited Before The Animation Has Finished If a state has property assignments, and the transition into the state has animations for the properties, the state can potentially be exited before the properties have been assigned to the @@ -545,7 +541,7 @@ If the target state does not assign any value to the property, there are two options: By default, the property will be assigned the value defined by the state it is leaving - (the value it would have been assigned if the animation had been permitted to finish playing.) If + (the value it would have been assigned if the animation had been permitted to finish playing). If a global restore policy is set, however, this will take precedence, and the property will be restored as usual. diff --git a/doc/src/snippets/statemachine/main2.cpp b/doc/src/snippets/statemachine/main2.cpp index 2419dc2..9a2890f 100644 --- a/doc/src/snippets/statemachine/main2.cpp +++ b/doc/src/snippets/statemachine/main2.cpp @@ -69,17 +69,18 @@ int main(int argv, char **args) //![1] QButton *interruptButton = new QPushButton("Interrupt Button"); + QWidget *mainWindow = new QWidget(); //![3] QHistoryState *s1h = new QHistoryState(s1); QState *s3 = new QState(); s3->assignProperty(label, "text", "In s3"); - QMessageBox mbox; - mbox.addButton(QMessageBox::Ok); - mbox.setText("Interrupted!"); - mbox.setIcon(QMessageBox::Information); - QObject::connect(s3, SIGNAL(entered()), &mbox, SLOT(exec())); + QMessageBox *mbox = new QMessageBox(mainWindow); + mbox->addButton(QMessageBox::Ok); + mbox->setText("Interrupted!"); + mbox->setIcon(QMessageBox::Information); + QObject::connect(s3, SIGNAL(entered()), mbox, SLOT(exec())); s3->addTransition(s1h); machine.addState(s3); diff --git a/doc/src/snippets/statemachine/main5.cpp b/doc/src/snippets/statemachine/main5.cpp index a9d4091..346cbce 100644 --- a/doc/src/snippets/statemachine/main5.cpp +++ b/doc/src/snippets/statemachine/main5.cpp @@ -44,14 +44,13 @@ int main(int argv, char **args) { QApplication app(argv, args); + QWidget *button; { //![0] QStateMachine machine; machine.setGlobalRestorePolicy(QStateMachine::RestoreProperties); -//![0] -//![1] QState *s1 = new QState(); s1->assignProperty(object, "fooBar", 1.0); machine.addState(s1); @@ -59,7 +58,7 @@ int main(int argv, char **args) QState *s2 = new QState(); machine.addState(s2); -//![1] +//![0] } { @@ -110,21 +109,50 @@ int main(int argv, char **args) } { + QMainWindow *mainWindow = 0; //![5] + QMessageBox *messageBox = new QMessageBox(mainWindow); + messageBox->addButton(QMessageBox::Ok); + messageBox->setText("Button geometry has been set!"); + messageBox->setIcon(QMessageBox::Information); + QState *s1 = new QState(); - s1->assignProperty(button, "geometry", QRectF(0, 0, 50, 50)); QState *s2 = new QState(); + s2->assignProperty(button, "geometry", QRectF(0, 0, 50, 50)); + connect(s2, SIGNAL(entered()), messageBox, SLOT(exec())); - s1->addTransition(s1, SIGNAL(polished()), s2); + s1->addTransition(button, SIGNAL(clicked()), s2); //![5] - } { + QMainWindow *mainWindow = 0; + +//![6] + QMessageBox *messageBox = new QMessageBox(mainWindow); + messageBox->addButton(QMessageBox::Ok); + messageBox->setText("Button geometry has been set!"); + messageBox->setIcon(QMessageBox::Information); + + QState *s1 = new QState(); + + QState *s2 = new QState(); + s2->assignProperty(button, "geometry", QRectF(0, 0, 50, 50)); + + QState *s3 = new QState(); + connect(s3, SIGNAL(entered()), messageBox, SLOT(exec())); + s1->addTransition(button, SIGNAL(clicked()), s2); + s2->addTransition(s2, SIGNAL(polished()), s3); //![6] + + } + + { + +//![7] QState *s1 = new QState(); QState *s2 = new QState(); @@ -134,10 +162,12 @@ int main(int argv, char **args) QStateMachine machine; machine.setInitialState(s1); machine.addDefaultAnimation(new QPropertyAnimation(object, "fooBar")); -//![6] +//![7] } + + return app.exec(); } -- cgit v0.12 From 1fd46b4495241ed03371fb5c86965b788791b363 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Tue, 3 Nov 2009 11:45:16 +0100 Subject: Embed code examples in state machine overview If you put \snippet inside \code tags, it's interpreted as code, not as a tag. Reviewed-by: Trust me --- doc/src/frameworks-technologies/statemachine.qdoc | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/doc/src/frameworks-technologies/statemachine.qdoc b/doc/src/frameworks-technologies/statemachine.qdoc index ac10314..9614dd3 100644 --- a/doc/src/frameworks-technologies/statemachine.qdoc +++ b/doc/src/frameworks-technologies/statemachine.qdoc @@ -426,9 +426,8 @@ value of the property before any property assignments in states were executed.) Take the following code: - \code - \snippet doc/src/snippets/statemachine/main5.cpp 0 - \endcode + + \snippet doc/src/snippets/statemachine/main5.cpp 0 Lets say the property \c fooBar is 0.0 when the machine starts. When the machine is in state \c s1, the property will be 1.0, since the state explicitly assigns this value to it. When the @@ -437,9 +436,8 @@ If we are using nested states, the parent defines a value for the property which is inherited by all descendants that do not explicitly assign a value to the property. - \code + \snippet doc/src/snippets/statemachine/main5.cpp 2 - \endcode Here \c s1 has two children: \c s2 and \c s3. When \c s2 is entered, the property \c fooBar will have the value 2.0, since this is explicitly defined for the state. When the machine is in @@ -452,9 +450,8 @@ properties as they are assigned in states. Say we have the following code: - \code + \snippet doc/src/snippets/statemachine/main5.cpp 3 - \endcode Here we define two states of a user interface. In \c s1 the \c button is small, and in \c s2 it is bigger. If we click the button to transition from \c s1 to \c s2, the geometry of the button @@ -462,9 +459,7 @@ smooth, however, all we need to do is make a QPropertyAnimation and add this to the transition object. - \code \snippet doc/src/snippets/statemachine/main5.cpp 4 - \endcode Adding an animation for the property in question means that the property assignment will no longer take immediate effect when the state has been entered. Instead, the animation will start @@ -486,9 +481,8 @@ the value defined by a state. Say we have the following code: - \code + \snippet doc/src/snippets/statemachine/main5.cpp 5 - \endcode When \c button is clicked, the machine will transition into state \c s2, which will set the geometry of the button, and then pop up a message box to alert the user that the geometry has @@ -504,9 +498,8 @@ value, we can use the state's polished() signal. The polished() signal will be emitted when the the property is assigned its final value, whether this is done immediately or after the animation has finished playing. - \code + \snippet doc/src/snippets/statemachine/main5.cpp 6 - \endcode In this example, when \c button is clicked, the machine will enter \c s2. It will remain in state \c s2 until the \c geometry property has been set to \c QRect(0, 0, 50, 50). Then it will -- cgit v0.12 From 68be6457f6732437b485812ab2db11c147a24b51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Trond=20Kjern=C3=A5sen?= Date: Tue, 3 Nov 2009 12:15:53 +0100 Subject: Removed usage of CompositionMode_Source in QGraphicsView for X11. Due to the rendering model in XRender ((src IN mask) OP dest) we can't support the PorterDuff composition modes natively under X11. They just behave differently than what we've defined them to do in QPainter, and there is no apparent workaround. Task-number: QTBUG-4829 Reviewed-by: Gunnar --- src/gui/graphicsview/qgraphicsview.cpp | 8 +++++++- src/gui/painting/qpainter.cpp | 5 +++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp index 710c745..8945f51 100644 --- a/src/gui/graphicsview/qgraphicsview.cpp +++ b/src/gui/graphicsview/qgraphicsview.cpp @@ -281,6 +281,7 @@ static const int QGRAPHICSVIEW_PREALLOC_STYLE_OPTIONS = 503; // largest prime < #include #include #ifdef Q_WS_X11 +#include #include #endif @@ -3294,7 +3295,12 @@ void QGraphicsView::paintEvent(QPaintEvent *event) backgroundPainter.setClipRegion(d->backgroundPixmapExposed, Qt::ReplaceClip); if (viewTransformed) backgroundPainter.setTransform(viewTransform); - backgroundPainter.setCompositionMode(QPainter::CompositionMode_Source); +#ifdef Q_WS_X11 +#undef X11 + if (backgroundPainter.paintEngine()->type() != QPaintEngine::X11) +#define X11 qt_x11Data +#endif + backgroundPainter.setCompositionMode(QPainter::CompositionMode_Source); drawBackground(&backgroundPainter, exposedSceneRect); d->backgroundPixmapExposed = QRegion(); } diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index cddad7d..8d6cad3 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -2275,8 +2275,9 @@ void QPainter::setBrushOrigin(const QPointF &p) /*! Sets the composition mode to the given \a mode. - \warning You can only set the composition mode for QPainter - objects that operates on a QImage. + \warning Only a QPainter operating on a QImage fully supports all + composition modes. The RasterOp modes are supported for X11 as + described in compositionMode(). \sa compositionMode() */ -- cgit v0.12