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 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