summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJens Bache-Wiig <jbache@trolltech.com>2010-09-19 12:41:55 +0200
committerJens Bache-Wiig <jbache@trolltech.com>2010-09-19 12:41:55 +0200
commita66c253d8229fcd6236cba8e98428f23970e0ad0 (patch)
treea4ff34f9f6042b0e8a6f4eda6c5930b6ffeef73e
parent61022aa56866636c00b9b3aff3d3106b9ef64419 (diff)
Improved shadowBlur
- Improved performance after some tips from sroedal - More stability
-rw-r--r--examples/painting/painting.qml8
-rw-r--r--src/context2d.cpp140
-rw-r--r--src/context2d.h7
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;