summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjørn Erik Nilsen <bjorn.nilsen@nokia.com>2009-08-21 09:33:44 (GMT)
committerBjørn Erik Nilsen <bjorn.nilsen@nokia.com>2009-08-21 11:51:32 (GMT)
commit00d7d50cde5d1e491039149d58502e17dba9b3b7 (patch)
treeba59ef8f83677c0c7c74b7db2f3f7a55c2887c16
parent487f636523dfded4c07a39e4d96ab3e83c64f95e (diff)
downloadQt-00d7d50cde5d1e491039149d58502e17dba9b3b7.zip
Qt-00d7d50cde5d1e491039149d58502e17dba9b3b7.tar.gz
Qt-00d7d50cde5d1e491039149d58502e17dba9b3b7.tar.bz2
Use pixmap filter for the drop shadow effect.
-rw-r--r--examples/effects/lighting/shadoweffect.cpp6
-rw-r--r--examples/effects/lighting/shadoweffect.h1
-rw-r--r--src/gui/effects/qgraphicseffect.cpp155
-rw-r--r--src/gui/effects/qgraphicseffect.h24
-rw-r--r--src/gui/effects/qgraphicseffect_p.h10
-rw-r--r--tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp2
6 files changed, 48 insertions, 150 deletions
diff --git a/examples/effects/lighting/shadoweffect.cpp b/examples/effects/lighting/shadoweffect.cpp
index 9545815..8a41aaa 100644
--- a/examples/effects/lighting/shadoweffect.cpp
+++ b/examples/effects/lighting/shadoweffect.cpp
@@ -48,17 +48,19 @@ ShadowEffect::ShadowEffect(QGraphicsItem *item, QGraphicsItem *source)
, item(item), m_lightSource(source)
{
setBlurRadius(8);
+ m_color = color();
}
void ShadowEffect::adjustForItem()
{
QPointF delta = item->pos() - m_lightSource->pos();
- setShadowOffset(delta.toPoint() / 30);
+ setOffset(delta.toPoint() / 30);
qreal dx = delta.x();
qreal dy = delta.y();
qreal dd = sqrt(dx * dx + dy * dy);
- setOpacity(qBound(0.4, 1 - dd / 200.0, 0.7));
+ m_color.setAlphaF(qBound(0.4, 1 - dd / 200.0, 0.7));
+ setColor(m_color);
}
QRectF ShadowEffect::boundingRectFor(const QRectF &rect) const
diff --git a/examples/effects/lighting/shadoweffect.h b/examples/effects/lighting/shadoweffect.h
index b20f647..7ea409e 100644
--- a/examples/effects/lighting/shadoweffect.h
+++ b/examples/effects/lighting/shadoweffect.h
@@ -58,6 +58,7 @@ private:
void adjustForItem();
private:
+ QColor m_color;
QGraphicsItem *item;
QGraphicsItem *m_lightSource;
};
diff --git a/src/gui/effects/qgraphicseffect.cpp b/src/gui/effects/qgraphicseffect.cpp
index 3d363f1..949922a 100644
--- a/src/gui/effects/qgraphicseffect.cpp
+++ b/src/gui/effects/qgraphicseffect.cpp
@@ -432,71 +432,6 @@ QGraphicsBlurEffect::~QGraphicsBlurEffect()
{
}
-// Blur the image according to the blur radius
-// Based on exponential blur algorithm by Jani Huhtanen
-// (maximum radius is set to 16)
-static QImage blurred(const QImage& image, const QRect& rect, int radius)
-{
- int tab[] = { 14, 10, 8, 6, 5, 5, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 };
- int alpha = (radius < 1) ? 16 : (radius > 17) ? 1 : tab[radius-1];
-
- QImage result = image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
- int r1 = rect.top();
- int r2 = rect.bottom();
- int c1 = rect.left();
- int c2 = rect.right();
-
- int bpl = result.bytesPerLine();
- int rgba[4];
- unsigned char* p;
-
- for (int col = c1; col <= c2; col++) {
- p = result.scanLine(r1) + col * 4;
- for (int i = 0; i < 4; i++)
- rgba[i] = p[i] << 4;
-
- p += bpl;
- for (int j = r1; j < r2; j++, p += bpl)
- for (int i = 0; i < 4; i++)
- p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4;
- }
-
- for (int row = r1; row <= r2; row++) {
- p = result.scanLine(row) + c1 * 4;
- for (int i = 0; i < 4; i++)
- rgba[i] = p[i] << 4;
-
- p += 4;
- for (int j = c1; j < c2; j++, p += 4)
- for (int i = 0; i < 4; i++)
- p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4;
- }
-
- for (int col = c1; col <= c2; col++) {
- p = result.scanLine(r2) + col * 4;
- for (int i = 0; i < 4; i++)
- rgba[i] = p[i] << 4;
-
- p -= bpl;
- for (int j = r1; j < r2; j++, p -= bpl)
- for (int i = 0; i < 4; i++)
- p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4;
- }
-
- for (int row = r1; row <= r2; row++) {
- p = result.scanLine(row) + c2 * 4;
- for (int i = 0; i < 4; i++)
- rgba[i] = p[i] << 4;
-
- p -= 4;
- for (int j = c1; j < c2; j++, p -= 4)
- for (int i = 0; i < 4; i++)
- p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4;
- }
-
- return result;
-}
-
int QGraphicsBlurEffect::blurRadius() const
{
Q_D(const QGraphicsBlurEffect);
@@ -553,121 +488,83 @@ QGraphicsDropShadowEffect::~QGraphicsDropShadowEffect()
{
}
-QPointF QGraphicsDropShadowEffect::shadowOffset() const
+QPointF QGraphicsDropShadowEffect::offset() const
{
Q_D(const QGraphicsDropShadowEffect);
- return d->offset;
+ return d->filter->offset();
}
-void QGraphicsDropShadowEffect::setShadowOffset(const QPointF &ofs)
+void QGraphicsDropShadowEffect::setOffset(const QPointF &ofs)
{
Q_D(QGraphicsDropShadowEffect);
- if (d->offset == ofs)
+ if (d->filter->offset() == ofs)
return;
- d->offset = ofs;
+ d->filter->setOffset(ofs);
updateBoundingRect();
- emit shadowOffsetChanged(ofs);
+ emit offsetChanged(ofs);
}
int QGraphicsDropShadowEffect::blurRadius() const
{
Q_D(const QGraphicsDropShadowEffect);
- return d->radius;
+ return d->filter->blurRadius();
}
void QGraphicsDropShadowEffect::setBlurRadius(int blurRadius)
{
Q_D(QGraphicsDropShadowEffect);
- if (d->radius == blurRadius)
+ if (d->filter->blurRadius() == blurRadius)
return;
- d->radius = blurRadius;
+ d->filter->setBlurRadius(blurRadius);
updateBoundingRect();
emit blurRadiusChanged(blurRadius);
}
-qreal QGraphicsDropShadowEffect::opacity() const
+QColor QGraphicsDropShadowEffect::color() const
{
Q_D(const QGraphicsDropShadowEffect);
- return d->alpha;
+ return d->filter->color();
}
-void QGraphicsDropShadowEffect::setOpacity(qreal opacity)
+void QGraphicsDropShadowEffect::setColor(const QColor &color)
{
Q_D(QGraphicsDropShadowEffect);
- if (qFuzzyCompare(d->alpha, opacity))
+ if (d->filter->color() == color)
return;
- d->alpha = opacity;
- emit opacityChanged(opacity);
+ d->filter->setColor(color);
+ emit colorChanged(color);
}
QRectF QGraphicsDropShadowEffect::boundingRectFor(const QRectF &rect) const
{
Q_D(const QGraphicsDropShadowEffect);
- QRectF shadowRect = rect.translated(d->offset);
- QRectF blurRect = shadowRect;
- qreal delta = d->radius * 3;
- blurRect.adjust(-delta, -delta, delta, delta);
- blurRect |= rect;
- return blurRect;
+ return d->filter->boundingRectFor(rect);
}
void QGraphicsDropShadowEffect::draw(QPainter *painter, QGraphicsEffectSource *source)
{
Q_D(QGraphicsDropShadowEffect);
- if (d->radius <= 0 && d->offset.isNull()) {
+ if (d->filter->blurRadius() <= 0 && d->filter->offset().isNull()) {
source->draw(painter);
return;
}
- const QTransform &transform = painter->worldTransform();
- const QPointF offset(d->offset.x() * transform.m11(), d->offset.y() * transform.m22());
- const QPoint shadowOffset = offset.toPoint();
- const QRectF sourceRect = source->boundingRect(Qt::DeviceCoordinates);
- const QRectF shadowRect = sourceRect.translated(offset);
-
- QRectF blurRect = shadowRect;
- qreal delta = d->radius * 3;
- blurRect.adjust(-delta, -delta, delta, delta);
- blurRect |= sourceRect;
-
- QRect effectRect = blurRect.toAlignedRect();
- const QRect deviceRect = source->deviceRect();
- const bool fullyInsideDeviceRect = effectRect.x() >= deviceRect.x()
- && effectRect.right() <= deviceRect.right()
- && effectRect.y() >= deviceRect.y()
- && effectRect.bottom() <= deviceRect.bottom();
- if (!fullyInsideDeviceRect) {
- // Clip to device rect to avoid huge pixmaps.
- effectRect &= source->deviceRect();
- effectRect |= effectRect.translated(-shadowOffset);
- if (effectRect.isEmpty())
- return; // nothing to paint;
+ QPoint offset;
+ if (source->isPixmap()) {
+ // No point in drawing in device coordinates (pixmap will be scaled anyways).
+ const QPixmap pixmap = source->pixmap(Qt::LogicalCoordinates, &offset);
+ d->filter->draw(painter, offset, pixmap);
+ return;
}
- QPixmap pixmap(effectRect.size());
- pixmap.fill(Qt::transparent);
- QPainter pixmapPainter(&pixmap);
- pixmapPainter.setRenderHints(painter->renderHints());
- pixmapPainter.setWorldTransform(painter->worldTransform());
- if (effectRect.x() != 0 || effectRect.y() != 0)
- pixmapPainter.translate(-effectRect.topLeft());
- source->draw(&pixmapPainter);
- pixmapPainter.end();
-
- QImage img = pixmap.toImage();
- QImage shadowImage(img.size(), QImage::Format_ARGB32);
- shadowImage.fill(qRgba(0, 0, 0, d->alpha * 255));
- shadowImage.setAlphaChannel(img.alphaChannel());
- shadowImage = blurred(shadowImage, shadowImage.rect(), d->radius);
-
- // Draw using an untransformed painter.
+ // Draw pixmap in device coordinates to avoid pixmap scaling.
+ const QPixmap pixmap = source->pixmap(Qt::DeviceCoordinates, &offset);
QTransform restoreTransform = painter->worldTransform();
painter->setWorldTransform(QTransform());
- painter->drawImage(effectRect.topLeft() + shadowOffset, shadowImage);
- painter->drawPixmap(effectRect.topLeft(), pixmap);
+ d->filter->draw(painter, offset, pixmap);
painter->setWorldTransform(restoreTransform);
}
diff --git a/src/gui/effects/qgraphicseffect.h b/src/gui/effects/qgraphicseffect.h
index f6c47d7..99d8548 100644
--- a/src/gui/effects/qgraphicseffect.h
+++ b/src/gui/effects/qgraphicseffect.h
@@ -235,31 +235,31 @@ class QGraphicsDropShadowEffectPrivate;
class Q_GUI_EXPORT QGraphicsDropShadowEffect: public QGraphicsEffect
{
Q_OBJECT
- Q_PROPERTY(QPointF shadowOffset READ shadowOffset WRITE setShadowOffset NOTIFY shadowOffsetChanged)
+ Q_PROPERTY(QPointF offset READ offset WRITE setOffset NOTIFY offsetChanged)
Q_PROPERTY(int blurRadius READ blurRadius WRITE setBlurRadius NOTIFY blurRadiusChanged)
- Q_PROPERTY(int opacity READ opacity WRITE setOpacity NOTIFY opacityChanged)
+ Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
public:
QGraphicsDropShadowEffect(QObject *parent = 0);
~QGraphicsDropShadowEffect();
QRectF boundingRectFor(const QRectF &rect) const;
- QPointF shadowOffset() const;
+ QPointF offset() const;
int blurRadius() const;
- qreal opacity() const;
+ QColor color() const;
public Q_SLOTS:
- void setShadowOffset(const QPointF &ofs);
- inline void setShadowOffset(qreal dx, qreal dy)
- { setShadowOffset(QPointF(dx, dy)); }
- inline void setShadowOffset(qreal d)
- { setShadowOffset(QPointF(d, d)); }
+ void setOffset(const QPointF &ofs);
+ inline void setOffset(qreal dx, qreal dy)
+ { setOffset(QPointF(dx, dy)); }
+ inline void setOffset(qreal d)
+ { setOffset(QPointF(d, d)); }
void setBlurRadius(int blurRadius);
- void setOpacity(qreal opacity);
+ void setColor(const QColor &color);
Q_SIGNALS:
- void shadowOffsetChanged(const QPointF &offset);
+ void offsetChanged(const QPointF &offset);
void blurRadiusChanged(int blurRadius);
- void opacityChanged(int opacity);
+ void colorChanged(const QColor &color);
protected:
void draw(QPainter *painter, QGraphicsEffectSource *source);
diff --git a/src/gui/effects/qgraphicseffect_p.h b/src/gui/effects/qgraphicseffect_p.h
index 25397c3..35f2d40 100644
--- a/src/gui/effects/qgraphicseffect_p.h
+++ b/src/gui/effects/qgraphicseffect_p.h
@@ -144,22 +144,20 @@ class QGraphicsBlurEffectPrivate : public QGraphicsEffectPrivate
{
Q_DECLARE_PUBLIC(QGraphicsBlurEffect)
public:
- QGraphicsBlurEffectPrivate() : filter(new QPixmapBlurFilter), blurRadius(4) {}
+ QGraphicsBlurEffectPrivate() : filter(new QPixmapBlurFilter) {}
~QGraphicsBlurEffectPrivate() { delete filter; }
QPixmapBlurFilter *filter;
- int blurRadius;
};
class QGraphicsDropShadowEffectPrivate : public QGraphicsEffectPrivate
{
Q_DECLARE_PUBLIC(QGraphicsDropShadowEffect)
public:
- QGraphicsDropShadowEffectPrivate() : offset(4, 4), radius(8), alpha(0.7) {}
+ QGraphicsDropShadowEffectPrivate() : filter(new QPixmapDropShadowFilter) {}
+ ~QGraphicsDropShadowEffectPrivate() { delete filter; }
- QPointF offset;
- int radius;
- qreal alpha;
+ QPixmapDropShadowFilter *filter;
};
QT_END_NAMESPACE
diff --git a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp
index 931e2d3..c335f16 100644
--- a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp
+++ b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp
@@ -7420,7 +7420,7 @@ void tst_QGraphicsItem::hitTestGraphicsEffectItem()
// Apply shadow effect to the entire sub-tree.
QGraphicsDropShadowEffect *shadow = new QGraphicsDropShadowEffect;
- shadow->setShadowOffset(-20, -20);
+ shadow->setOffset(-20, -20);
item1->setGraphicsEffect(shadow);
QTest::qWait(50);