diff options
author | Jens Bache-Wiig <jbache@trolltech.com> | 2010-09-19 12:41:55 +0200 |
---|---|---|
committer | Jens Bache-Wiig <jbache@trolltech.com> | 2010-09-19 12:41:55 +0200 |
commit | a66c253d8229fcd6236cba8e98428f23970e0ad0 (patch) | |
tree | a4ff34f9f6042b0e8a6f4eda6c5930b6ffeef73e | |
parent | 61022aa56866636c00b9b3aff3d3106b9ef64419 (diff) |
Improved shadowBlur
- Improved performance after some tips from sroedal
- More stability
-rw-r--r-- | examples/painting/painting.qml | 8 | ||||
-rw-r--r-- | src/context2d.cpp | 140 | ||||
-rw-r--r-- | src/context2d.h | 7 |
3 files changed, 78 insertions, 77 deletions
diff --git a/examples/painting/painting.qml b/examples/painting/painting.qml index 9aa8ee4..a3aacdd 100644 --- a/examples/painting/painting.qml +++ b/examples/painting/painting.qml @@ -63,10 +63,10 @@ Rectangle { var ctx = getContext("2d"); // Here we copy contents from drawing and apply drop shaddow var img = canvas.toImage(); - ctx.shadowOffsetX = 4; - ctx.shadowOffsetY = 4; - ctx.shadowBlur = 20; - ctx.shadowColor = "red"; + ctx.shadowOffsetX = 1; + ctx.shadowOffsetY = 1; + ctx.shadowBlur = 8; + ctx.shadowColor = "black"; ctx.drawImage(img, 25, 25, width-50, height-50); } } diff --git a/src/context2d.cpp b/src/context2d.cpp index 52d0864..69cee66 100644 --- a/src/context2d.cpp +++ b/src/context2d.cpp @@ -56,6 +56,7 @@ public: // Note, this is exported but in a private header as qtopengl depends on it. // But it really should be considered private API void qt_blurImage(QPainter *p, QImage &blurImage, qreal radius, bool quality, bool alphaOnly, int transposed = 0); +void qt_blurImage(QImage &blurImage, qreal radius, bool quality, int transposed = 0); #define DEGREES(t) ((t) * 180.0 / Q_PI) @@ -443,24 +444,32 @@ void Context2D::setMiterLimit(qreal m) void Context2D::setShadowOffsetX(qreal x) { + if (m_painter.device() == &m_shadowbuffer && m_state.shadowBlur>0) + endPainting(); m_state.shadowOffsetX = x; m_state.flags |= DirtyShadowOffsetX; } void Context2D::setShadowOffsetY(qreal y) { + if (m_painter.device() == &m_shadowbuffer && m_state.shadowBlur>0) + endPainting(); m_state.shadowOffsetY = y; m_state.flags |= DirtyShadowOffsetY; } void Context2D::setShadowBlur(qreal b) { + if (m_painter.device() == &m_shadowbuffer && m_state.shadowBlur>0) + endPainting(); m_state.shadowBlur = b; m_state.flags |= DirtyShadowBlur; } void Context2D::setShadowColor(const QString &str) { + if (m_painter.device() == &m_shadowbuffer && m_state.shadowBlur>0) + endPainting(); m_state.shadowColor = colorFromString(str); m_state.flags |= DirtyShadowColor; } @@ -688,6 +697,32 @@ Context2D::Context2D(QObject *parent) reset(); } +void Context2D::setupPainter() +{ + if ((m_state.flags & DirtyClippingRegion) && !m_state.clipPath.isEmpty()) + m_painter.setClipPath(m_state.clipPath); + if (m_state.flags & DirtyFillStyle) + m_painter.setBrush(m_state.fillStyle); + if (m_state.flags & DirtyGlobalAlpha) + m_painter.setOpacity(m_state.globalAlpha); + if (m_state.flags & DirtyGlobalCompositeOperation) + m_painter.setCompositionMode(m_state.globalCompositeOperation); + if (m_state.flags & MDirtyPen) { + QPen pen = m_painter.pen(); + if (m_state.flags & DirtyStrokeStyle) + pen.setBrush(m_state.strokeStyle); + if (m_state.flags & DirtyLineWidth) + pen.setWidthF(m_state.lineWidth); + if (m_state.flags & DirtyLineCap) + pen.setCapStyle(m_state.lineCap); + if (m_state.flags & DirtyLineJoin) + pen.setJoinStyle(m_state.lineJoin); + if (m_state.flags & DirtyMiterLimit) + pen.setMiterLimit(m_state.miterLimit); + m_painter.setPen(pen); + } +} + void Context2D::beginPainting() { if (m_width <= 0 || m_height <=0) @@ -699,17 +734,20 @@ void Context2D::beginPainting() } if (m_state.shadowBlur > 0) { - if (m_shadowbuffer.width() != m_width || m_shadowbuffer.height() != m_height) - m_shadowbuffer = QPixmap(m_width, m_height); - m_shadowbuffer.fill(Qt::transparent); + if (m_shadowbuffer.width() != m_width || m_shadowbuffer.height() != m_height) { + m_shadowbuffer = QImage(m_width, m_height, QImage::Format_ARGB32); + m_shadowbuffer.fill(Qt::transparent); + } } if (!m_painter.isActive()) { + if (m_state.shadowBlur == 0) m_painter.begin(&m_pixmap); - else + else { + m_shadowbuffer.fill(Qt::transparent); m_painter.begin(&m_shadowbuffer); - + } m_painter.setRenderHint(QPainter::Antialiasing); if (!m_state.clipPath.isEmpty()) m_painter.setClipPath(m_state.clipPath); @@ -725,89 +763,49 @@ void Context2D::beginPainting() pen.setMiterLimit(m_state.miterLimit); m_painter.setPen(pen); } else { - if ((m_state.flags & DirtyClippingRegion) && !m_state.clipPath.isEmpty()) - m_painter.setClipPath(m_state.clipPath); - if (m_state.flags & DirtyFillStyle) - m_painter.setBrush(m_state.fillStyle); - if (m_state.flags & DirtyGlobalAlpha) - m_painter.setOpacity(m_state.globalAlpha); - if (m_state.flags & DirtyGlobalCompositeOperation) - m_painter.setCompositionMode(m_state.globalCompositeOperation); - if (m_state.flags & MDirtyPen) { - QPen pen = m_painter.pen(); - if (m_state.flags & DirtyStrokeStyle) - pen.setBrush(m_state.strokeStyle); - if (m_state.flags & DirtyLineWidth) - pen.setWidthF(m_state.lineWidth); - if (m_state.flags & DirtyLineCap) - pen.setCapStyle(m_state.lineCap); - if (m_state.flags & DirtyLineJoin) - pen.setJoinStyle(m_state.lineJoin); - if (m_state.flags & DirtyMiterLimit) - pen.setMiterLimit(m_state.miterLimit); - m_painter.setPen(pen); - } + setupPainter(); m_state.flags = 0; } } void Context2D::endPainting() { - if (m_painter.isActive()) - m_painter.end(); - if (m_state.shadowBlur > 0) { - m_painter.begin(&m_pixmap); - - // Draw shadow - QImage tmp(m_shadowbuffer.size(), QImage::Format_ARGB32_Premultiplied); - tmp.fill(Qt::transparent); - QRect imageRect = m_pixmap.rect(); + QImage alphaChannel = m_shadowbuffer.alphaChannel(); + qt_blurImage(alphaChannel, m_state.shadowBlur, false, 1); - QPainter tmpPainter(&tmp); - tmpPainter.setCompositionMode(QPainter::CompositionMode_Source); - tmpPainter.drawPixmap(0, 0, m_shadowbuffer); - tmpPainter.end(); + QRect imageRect = m_shadowbuffer.rect(); - // blur the alpha channel - QImage blurred(tmp.size(), QImage::Format_ARGB32_Premultiplied); - blurred.fill(Qt::transparent); - QPainter blurPainter(&blurred); - qt_blurImage(&blurPainter, tmp, m_state.shadowBlur, false, true); - blurPainter.end(); + if (m_shadowColorIndexBuffer.isEmpty() || m_shadowColorBuffer != m_state.shadowColor) { + m_shadowColorIndexBuffer.clear(); + m_shadowColorBuffer = m_state.shadowColor; - tmp = blurred; + for (int i = 0; i < 256; ++i) { + m_shadowColorIndexBuffer << qRgba(qRound(255 * m_state.shadowColor.redF()), + qRound(255 * m_state.shadowColor.greenF()), + qRound(255 * m_state.shadowColor.blueF()), + i); + } + } + alphaChannel.setColorTable(m_shadowColorIndexBuffer); - // blacken the image... - tmpPainter.begin(&tmp); - tmpPainter.setCompositionMode(QPainter::CompositionMode_SourceIn); - tmpPainter.fillRect(imageRect, m_state.shadowColor); - tmpPainter.end(); + if (m_painter.isActive()) + m_painter.end(); - tmpPainter.begin(&tmp); - tmpPainter.setCompositionMode(QPainter::CompositionMode_SourceIn); - tmpPainter.fillRect(imageRect, m_state.shadowColor); - tmpPainter.end(); + m_painter.begin(&m_pixmap); + setupPainter(); // draw the blurred drop shadow... - m_painter.drawImage(QRect(m_state.shadowOffsetX, m_state.shadowOffsetY, imageRect.width(), imageRect.height()), tmp); + QTransform tf = m_painter.transform(); + m_painter.translate(0, imageRect.height()); + m_painter.rotate(-90); + m_painter.drawImage(-m_state.shadowOffsetY, m_state.shadowOffsetX, alphaChannel); + m_painter.setTransform(tf); // draw source - m_painter.drawPixmap(0, 0, m_shadowbuffer); - /* - CustomDropShadowEffect *effect = new CustomDropShadowEffect; - effect->setBlurRadius(m_state.shadowBlur); - effect->setColor(m_state.shadowColor); - effect->setOffset(m_state.shadowOffsetX, m_state.shadowOffsetY); - effect->setEnabled(true); -*/ // QStyleOptionGraphicsItem option; - // QGraphicsPixmapItem *item = new QGraphicsPixmapItem(m_shadowbuffer, 0, 0); - // item->setGraphicsEffect(effect); - // effect->drawSource(&m_painter); - // option.rect = QRect(0, 0, m_pixmap.width(), m_pixmap.height()); - // item->setGraphicsEffect(0); - // item->paint(&m_painter, &option, 0); + m_painter.drawImage(0, 0, m_shadowbuffer.copy()); + m_painter.end(); } } diff --git a/src/context2d.h b/src/context2d.h index a8da860..5a8cdaf 100644 --- a/src/context2d.h +++ b/src/context2d.h @@ -134,7 +134,7 @@ public: void clear(); void reset(); - QPixmap pixmap() { endPainting(); return m_pixmap; } + QPixmap pixmap() { return m_pixmap; } // compositing qreal globalAlpha() const; // (default 1.0) @@ -225,6 +225,7 @@ signals: void changed(); private: + void setupPainter(); void beginPainting(); int m_changeTimerId; @@ -280,7 +281,9 @@ private: State m_state; QStack<State> m_stateStack; QPixmap m_pixmap; - QPixmap m_shadowbuffer; + QImage m_shadowbuffer; + QVector<QRgb> m_shadowColorIndexBuffer; + QColor m_shadowColorBuffer; QPainter m_painter; int m_width, m_height; bool m_inPaint; |