summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--examples/graphicsview/blurpicker/blureffect.cpp4
-rw-r--r--examples/graphicsview/blurpicker/blureffect.h2
-rw-r--r--examples/graphicsview/lighting/shadoweffect.cpp8
-rw-r--r--examples/graphicsview/lighting/shadoweffect.h4
-rw-r--r--src/corelib/global/qnamespace.h5
-rw-r--r--src/gui/graphicsview/qgraphicseffect.cpp409
-rw-r--r--src/gui/graphicsview/qgraphicseffect.h114
-rw-r--r--src/gui/graphicsview/qgraphicseffect_p.h41
-rw-r--r--src/gui/graphicsview/qgraphicsitem.cpp88
-rw-r--r--src/gui/graphicsview/qgraphicsitem.h1
-rw-r--r--src/gui/graphicsview/qgraphicsitem_p.h58
-rw-r--r--src/gui/graphicsview/qgraphicsscene.cpp86
-rw-r--r--src/gui/graphicsview/qgraphicsscene.h1
-rw-r--r--src/gui/graphicsview/qgraphicsscene_p.h6
-rw-r--r--src/opengl/qgraphicsshadereffect.cpp36
-rw-r--r--src/opengl/qgraphicsshadereffect.h2
16 files changed, 511 insertions, 354 deletions
diff --git a/examples/graphicsview/blurpicker/blureffect.cpp b/examples/graphicsview/blurpicker/blureffect.cpp
index 43791c6..82be44f 100644
--- a/examples/graphicsview/blurpicker/blureffect.cpp
+++ b/examples/graphicsview/blurpicker/blureffect.cpp
@@ -62,8 +62,8 @@ QRectF BlurEffect::boundingRect() const
return QGraphicsBlurEffect::boundingRect();
}
-void BlurEffect::draw(QPainter *painter)
+void BlurEffect::draw(QPainter *painter, QGraphicsEffectSource *source)
{
adjustForItem();
- QGraphicsBlurEffect::draw(painter);
+ QGraphicsBlurEffect::draw(painter, source);
}
diff --git a/examples/graphicsview/blurpicker/blureffect.h b/examples/graphicsview/blurpicker/blureffect.h
index 2aea8bf..89694b6 100644
--- a/examples/graphicsview/blurpicker/blureffect.h
+++ b/examples/graphicsview/blurpicker/blureffect.h
@@ -54,7 +54,7 @@ public:
QRectF boundingRect() const;
- void draw(QPainter *painter);
+ void draw(QPainter *painter, QGraphicsEffectSource *source);
private:
void adjustForItem();
diff --git a/examples/graphicsview/lighting/shadoweffect.cpp b/examples/graphicsview/lighting/shadoweffect.cpp
index e2dd864..f447531 100644
--- a/examples/graphicsview/lighting/shadoweffect.cpp
+++ b/examples/graphicsview/lighting/shadoweffect.cpp
@@ -61,14 +61,14 @@ void ShadowEffect::adjustForItem()
setOpacity(qBound(0.4, 1 - dd / 200.0, 0.7));
}
-QRectF ShadowEffect::boundingRect() const
+QRectF ShadowEffect::boundingRectFor(const QRectF &rect) const
{
const_cast<ShadowEffect *>(this)->adjustForItem();
- return QGraphicsShadowEffect::boundingRect();
+ return QGraphicsShadowEffect::boundingRectFor(rect);
}
-void ShadowEffect::draw(QPainter *painter)
+void ShadowEffect::draw(QPainter *painter, QGraphicsEffectSource *source)
{
adjustForItem();
- QGraphicsShadowEffect::draw(painter);
+ QGraphicsShadowEffect::draw(painter, source);
}
diff --git a/examples/graphicsview/lighting/shadoweffect.h b/examples/graphicsview/lighting/shadoweffect.h
index d4aa440..68318b0 100644
--- a/examples/graphicsview/lighting/shadoweffect.h
+++ b/examples/graphicsview/lighting/shadoweffect.h
@@ -50,9 +50,9 @@ class ShadowEffect: public QGraphicsShadowEffect
public:
ShadowEffect(QGraphicsItem *item, QGraphicsItem *source);
- QRectF boundingRect() const;
+ QRectF boundingRectFor(const QRectF &rect) const;
- void draw(QPainter *painter);
+ void draw(QPainter *painter, QGraphicsEffectSource *source);
private:
void adjustForItem();
diff --git a/src/corelib/global/qnamespace.h b/src/corelib/global/qnamespace.h
index 7770fd6..834ad1a 100644
--- a/src/corelib/global/qnamespace.h
+++ b/src/corelib/global/qnamespace.h
@@ -1552,6 +1552,11 @@ public:
Uninitialized
};
+ enum CoordinateSystem {
+ DeviceCoordinates,
+ LogicalCoordinates
+ };
+
enum TouchPointState {
TouchPointPressed = 0x01,
TouchPointMoved = 0x02,
diff --git a/src/gui/graphicsview/qgraphicseffect.cpp b/src/gui/graphicsview/qgraphicseffect.cpp
index 31a437a..45955f2 100644
--- a/src/gui/graphicsview/qgraphicseffect.cpp
+++ b/src/gui/graphicsview/qgraphicseffect.cpp
@@ -44,9 +44,8 @@
#ifndef QT_NO_GRAPHICSVIEW
#include <QtGui/qimage.h>
-#include <QtGui/qgraphicsitem.h>
-#include <QtGui/qgraphicsscene.h>
#include <QtGui/qpainter.h>
+#include <QtCore/qrect.h>
/*
@@ -102,13 +101,39 @@
*/
+QGraphicsEffectSource::QGraphicsEffectSource(QGraphicsEffectSourcePrivate &dd, QObject *parent)
+ : QObject(dd, parent)
+{}
+
+QGraphicsEffectSource::~QGraphicsEffectSource()
+{}
+
+QRectF QGraphicsEffectSource::boundingRect(Qt::CoordinateSystem system) const
+{ return d_func()->boundingRect(system); }
+
+const QGraphicsItem *QGraphicsEffectSource::graphicsItem() const
+{ return d_func()->graphicsItem(); }
+
+const QStyleOption *QGraphicsEffectSource::styleOption() const
+{ return d_func()->styleOption(); }
+
+void QGraphicsEffectSource::draw(QPainter *painter)
+{ d_func()->draw(painter); }
+
+void QGraphicsEffectSource::update()
+{ d_func()->update(); }
+
+bool QGraphicsEffectSource::isPixmap() const
+{ return d_func()->isPixmap(); }
+
+QPixmap QGraphicsEffectSource::pixmap(Qt::CoordinateSystem system, QPoint *offset) const
+{ return d_func()->pixmap(system, offset); }
+
+
QGraphicsEffect::QGraphicsEffect()
: QObject(*new QGraphicsEffectPrivate, 0)
{}
-/*!
- \internal
-*/
QGraphicsEffect::QGraphicsEffect(QGraphicsEffectPrivate &dd)
: QObject(dd, 0)
{}
@@ -121,32 +146,64 @@ QGraphicsEffect::~QGraphicsEffect()
QRectF QGraphicsEffect::boundingRect() const
{
- return sourceBoundingRect();
+ Q_D(const QGraphicsEffect);
+ if (d->source)
+ return boundingRectFor(d->source->boundingRect());
+ return QRectF();
+}
+
+void QGraphicsEffect::setSourcePixmap(const QPixmap &pixmap)
+{
+ Q_D(QGraphicsEffect);
+ d->sourcePixmap = pixmap;
+ d->hasSourcePixmap = !pixmap.isNull();
}
-QRectF QGraphicsEffect::sourceBoundingRect() const
+QPixmap QGraphicsEffect::sourcePixmap() const
{
Q_D(const QGraphicsEffect);
- if (d->source)
- return d->source->boundingRect();
- return QRectF();
+ return d->sourcePixmap;
+}
+
+bool QGraphicsEffect::hasSourcePixmap() const
+{
+ Q_D(const QGraphicsEffect);
+ return d->hasSourcePixmap;
}
-void QGraphicsEffect::drawSource(QPainter *painter)
+QRectF QGraphicsEffect::boundingRectFor(const QRectF &rect) const
+{
+ return rect;
+}
+
+void QGraphicsEffect::setEnabled(bool enable)
{
Q_D(QGraphicsEffect);
- if (d->source)
- d->source->draw(painter);
+ d->isEnabled = enable;
}
-bool QGraphicsEffect::drawSourceIntoPixmap(QPixmap *pixmap, const QTransform &itemToPixmapTransform)
+bool QGraphicsEffect::isEnabled() const
+{
+ Q_D(const QGraphicsEffect);
+ return d->isEnabled;
+}
+
+QGraphicsEffectSource *QGraphicsEffect::source() const
+{
+ Q_D(const QGraphicsEffect);
+ return d->source;
+}
+
+void QGraphicsEffect::updateBoundingRect()
{
Q_D(QGraphicsEffect);
if (d->source)
- return d->source->drawIntoPixmap(pixmap, itemToPixmapTransform);
- return false;
+ d->source->update();
}
+void QGraphicsEffect::sourceChanged(QGraphicsEffectSource *)
+{}
+
QGraphicsGrayscaleEffect::QGraphicsGrayscaleEffect()
: QGraphicsEffect(*new QGraphicsGrayscaleEffectPrivate)
{}
@@ -154,30 +211,22 @@ QGraphicsGrayscaleEffect::QGraphicsGrayscaleEffect()
QGraphicsGrayscaleEffect::~QGraphicsGrayscaleEffect()
{}
-void QGraphicsGrayscaleEffect::draw(QPainter *painter)
+void QGraphicsGrayscaleEffect::draw(QPainter *painter, QGraphicsEffectSource *source)
{
Q_D(QGraphicsGrayscaleEffect);
- if (!d->source)
- return;
-
- // Find the item's bounds in device coordinates.
- QTransform itemToPixmapTransform(painter->worldTransform());
- QRectF deviceBounds = itemToPixmapTransform.mapRect(d->source->boundingRect());
- QRect deviceRect = deviceBounds.toRect().adjusted(-1, -1, 1, 1);
- if (deviceRect.isEmpty())
- return;
-
- if (deviceRect.x() != 0 || deviceRect.y() != 0)
- itemToPixmapTransform *= QTransform::fromTranslate(-deviceRect.x(), -deviceRect.y());
-
- QPixmap pixmap(deviceRect.size());
- if (!d->source->drawIntoPixmap(&pixmap, itemToPixmapTransform))
+ 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, pixmap.rect());
return;
+ }
- // Draw the pixmap with the filter 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());
- d->filter->draw(painter, deviceRect.topLeft(), pixmap, pixmap.rect());
+ d->filter->draw(painter, offset, pixmap, pixmap.rect());
painter->setWorldTransform(restoreTransform);
}
@@ -201,30 +250,22 @@ void QGraphicsColorizeEffect::setColor(const QColor &c)
d->filter->setColor(c);
}
-void QGraphicsColorizeEffect::draw(QPainter *painter)
+void QGraphicsColorizeEffect::draw(QPainter *painter, QGraphicsEffectSource *source)
{
Q_D(QGraphicsColorizeEffect);
- if (!d->source)
- return;
-
- // Find the item's bounds in device coordinates.
- QTransform itemToPixmapTransform(painter->worldTransform());
- QRectF deviceBounds = itemToPixmapTransform.mapRect(d->source->boundingRect());
- QRect deviceRect = deviceBounds.toRect().adjusted(-1, -1, 1, 1);
- if (deviceRect.isEmpty())
- return;
-
- if (deviceRect.x() != 0 || deviceRect.y() != 0)
- itemToPixmapTransform *= QTransform::fromTranslate(-deviceRect.x(), -deviceRect.y());
-
- QPixmap pixmap(deviceRect.size());
- if (!d->source->drawIntoPixmap(&pixmap, itemToPixmapTransform))
+ 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, pixmap.rect());
return;
+ }
- // Draw the pixmap with the filter using an untransformed painter.
+ // Draw pixmap in deviceCoordinates to avoid pixmap scaling.
+ const QPixmap pixmap = source->pixmap(Qt::DeviceCoordinates, &offset);
QTransform restoreTransform = painter->worldTransform();
painter->setWorldTransform(QTransform());
- d->filter->draw(painter, deviceRect.topLeft(), pixmap, pixmap.rect());
+ d->filter->draw(painter, offset, pixmap, pixmap.rect());
painter->setWorldTransform(restoreTransform);
}
@@ -249,50 +290,54 @@ void QGraphicsPixelizeEffect::setPixelSize(int size)
d->pixelSize = size;
}
-void QGraphicsPixelizeEffect::draw(QPainter *painter)
+static inline void pixelize(QImage *image, int pixelSize)
+{
+ Q_ASSERT(pixelSize > 0);
+ Q_ASSERT(image);
+ int width = image->width();
+ int height = image->height();
+ for (int y = 0; y < height; y += pixelSize) {
+ int ys = qMin(height - 1, y + pixelSize / 2);
+ QRgb *sbuf = reinterpret_cast<QRgb*>(image->scanLine(ys));
+ for (int x = 0; x < width; x += pixelSize) {
+ int xs = qMin(width - 1, x + pixelSize / 2);
+ QRgb color = sbuf[xs];
+ for (int yi = 0; yi < qMin(pixelSize, height - y); ++yi) {
+ QRgb *buf = reinterpret_cast<QRgb*>(image->scanLine(y + yi));
+ for (int xi = 0; xi < qMin(pixelSize, width - x); ++xi)
+ buf[x + xi] = color;
+ }
+ }
+ }
+}
+
+void QGraphicsPixelizeEffect::draw(QPainter *painter, QGraphicsEffectSource *source)
{
Q_D(QGraphicsPixelizeEffect);
- if (!d->source)
+ if (d->pixelSize <= 0) {
+ source->draw(painter);
return;
+ }
- // Find the item's bounds in device coordinates.
- QTransform itemToPixmapTransform(painter->worldTransform());
- QRectF deviceBounds = itemToPixmapTransform.mapRect(d->source->boundingRect());
- QRect deviceRect = deviceBounds.toRect().adjusted(-1, -1, 1, 1);
- if (deviceRect.isEmpty())
+ QPoint offset;
+ if (source->isPixmap()) {
+ const QPixmap pixmap = source->pixmap(Qt::LogicalCoordinates, &offset);
+ QImage image = pixmap.toImage().convertToFormat(QImage::Format_ARGB32);
+ pixelize(&image, d->pixelSize);
+ painter->drawImage(offset, image);
return;
+ }
- if (deviceRect.x() != 0 || deviceRect.y() != 0)
- itemToPixmapTransform *= QTransform::fromTranslate(-deviceRect.x(), -deviceRect.y());
-
- QPixmap pixmap(deviceRect.size());
- if (!d->source->drawIntoPixmap(&pixmap))
- return;
+ // Draw pixmap in device coordinates to avoid pixmap scaling.
+ const QPixmap pixmap = source->pixmap(Qt::DeviceCoordinates, &offset);
// pixelize routine
- QImage img = pixmap.toImage().convertToFormat(QImage::Format_ARGB32);
- if (d->pixelSize > 0) {
- int width = img.width();
- int height = img.height();
- for (int y = 0; y < height; y += d->pixelSize) {
- int ys = qMin(height - 1, y + d->pixelSize / 2);
- QRgb *sbuf = reinterpret_cast<QRgb*>(img.scanLine(ys));
- for (int x = 0; x < width; x += d->pixelSize) {
- int xs = qMin(width - 1, x + d->pixelSize / 2);
- QRgb color = sbuf[xs];
- for (int yi = 0; yi < qMin(d->pixelSize, height - y); ++yi) {
- QRgb *buf = reinterpret_cast<QRgb*>(img.scanLine(y + yi));
- for (int xi = 0; xi < qMin(d->pixelSize, width - x); ++xi)
- buf[x + xi] = color;
- }
- }
- }
- }
+ QImage image = pixmap.toImage().convertToFormat(QImage::Format_ARGB32);
+ pixelize(&image, d->pixelSize);
- // Draw using an untransformed painter.
QTransform restoreTransform = painter->worldTransform();
painter->setWorldTransform(QTransform());
- painter->drawImage(deviceRect.topLeft(), img);
+ painter->drawImage(offset, image);
painter->setWorldTransform(restoreTransform);
}
@@ -380,44 +425,32 @@ void QGraphicsBlurEffect::setBlurRadius(int radius)
{
Q_D(QGraphicsBlurEffect);
d->filter->setRadius(radius);
+ updateBoundingRect();
}
-QRectF QGraphicsBlurEffect::boundingRect() const
+QRectF QGraphicsBlurEffect::boundingRectFor(const QRectF &rect) const
{
Q_D(const QGraphicsBlurEffect);
- if (d->source)
- return d->filter->boundingRectFor(d->source->boundingRect());
- return QRectF();
+ return d->filter->boundingRectFor(rect);
}
-void QGraphicsBlurEffect::draw(QPainter *painter)
+void QGraphicsBlurEffect::draw(QPainter *painter, QGraphicsEffectSource *source)
{
Q_D(QGraphicsBlurEffect);
- if (!d->source)
- return;
- // Find the item's bounds in device coordinates.
- QTransform itemToPixmapTransform(painter->worldTransform());
- QRectF deviceBounds = itemToPixmapTransform.mapRect(d->source->boundingRect());
- QRect deviceRect = deviceBounds.toRect().adjusted(-1, -1, 1, 1);
- if (deviceRect.isEmpty())
- return;
-
- // ### Potentially big rect; must be clipped to the viewport rect.
- const qreal delta = d->blurRadius * 3;
- const QRect effectRect = deviceBounds.adjusted(-delta, -delta, delta, delta)
- .toRect().adjusted(-1, -1, 1, 1);
- if (effectRect.x() != 0 || effectRect.y() != 0)
- itemToPixmapTransform *= QTransform::fromTranslate(-effectRect.x(), -effectRect.y());
-
- QPixmap pixmap(effectRect.size());
- if (!d->source->drawIntoPixmap(&pixmap, itemToPixmapTransform))
+ 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, pixmap.rect());
return;
+ }
- // Draw the pixmap with the filter 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());
- d->filter->draw(painter, deviceRect.topLeft(), pixmap, pixmap.rect());
+ d->filter->draw(painter, offset, pixmap, pixmap.rect());
painter->setWorldTransform(restoreTransform);
}
@@ -440,6 +473,7 @@ void QGraphicsBloomEffect::setBlurRadius(int radius)
{
Q_D(QGraphicsBloomEffect);
d->blurRadius = radius;
+ updateBoundingRect();
}
qreal QGraphicsBloomEffect::opacity() const
@@ -454,13 +488,11 @@ void QGraphicsBloomEffect::setOpacity(qreal alpha)
d->opacity = alpha;
}
-QRectF QGraphicsBloomEffect::boundingRect() const
+QRectF QGraphicsBloomEffect::boundingRectFor(const QRectF &rect) const
{
Q_D(const QGraphicsBloomEffect);
- if (!d->source)
- return QRectF();
- qreal delta = d->blurRadius * 3;
- return d->source->boundingRect().adjusted(-delta, -delta, delta, delta);
+ const qreal delta = d->blurRadius * 3;
+ return rect.adjusted(-delta, -delta, delta, delta);
}
// Change brightness (positive integer) of each pixel
@@ -494,28 +526,32 @@ static QImage composited(const QImage& img1, const QImage& img2, qreal opacity,
return result;
}
-void QGraphicsBloomEffect::draw(QPainter *painter)
+void QGraphicsBloomEffect::draw(QPainter *painter, QGraphicsEffectSource *source)
{
Q_D(QGraphicsBloomEffect);
- if (!d->source)
- return;
- // Find the item's bounds in device coordinates.
- QTransform itemToPixmapTransform(painter->worldTransform());
- QRectF deviceBounds = itemToPixmapTransform.mapRect(d->source->boundingRect());
- QRect deviceRect = deviceBounds.toRect().adjusted(-1, -1, 1, 1);
- if (deviceRect.isEmpty())
- return;
+ QPoint offset;
+ const int radius = d->blurRadius;
+ const int delta = radius * 3;
+
+ if (source->isPixmap()) {
+ // No point in drawing in device coordinates (pixmap will be scaled anyways).
+ const QPixmap pixmap = source->pixmap(Qt::LogicalCoordinates, &offset);
- if (deviceRect.x() != 0 || deviceRect.y() != 0)
- itemToPixmapTransform *= QTransform::fromTranslate(-deviceRect.x(), -deviceRect.y());
+ // bloom routine
+ QImage img = pixmap.toImage().convertToFormat(QImage::Format_ARGB32_Premultiplied);
+ QImage overlay = blurred(img, img.rect(), radius);
+ overlay = brightened(overlay, 70);
+ img = composited(img, overlay, d->opacity, QPainter::CompositionMode_Overlay);
- QPixmap pixmap(deviceRect.size());
- if (!d->source->drawIntoPixmap(&pixmap, itemToPixmapTransform))
+ painter->drawImage(offset - QPoint(delta, delta), img);
return;
+ }
+
+ // Draw pixmap in device coordinates to avoid pixmap scaling.
+ const QPixmap pixmap = source->pixmap(Qt::DeviceCoordinates, &offset);
// bloom routine
- int radius = d->blurRadius;
QImage img = pixmap.toImage().convertToFormat(QImage::Format_ARGB32_Premultiplied);
QImage overlay = blurred(img, img.rect(), radius);
overlay = brightened(overlay, 70);
@@ -524,7 +560,7 @@ void QGraphicsBloomEffect::draw(QPainter *painter)
// Draw using an untransformed painter.
QTransform restoreTransform = painter->worldTransform();
painter->setWorldTransform(QTransform());
- painter->drawImage(deviceRect.topLeft() - QPointF(radius * 3, radius * 3), img);
+ painter->drawImage(offset - QPoint(radius * 3, radius * 3), img);
painter->setWorldTransform(restoreTransform);
}
@@ -559,6 +595,7 @@ void QGraphicsFrameEffect::setFrameWidth(qreal frameWidth)
{
Q_D(QGraphicsFrameEffect);
d->width = frameWidth;
+ updateBoundingRect();
}
qreal QGraphicsFrameEffect::frameOpacity() const
@@ -573,49 +610,23 @@ void QGraphicsFrameEffect::setFrameOpacity(qreal opacity)
d->alpha = opacity;
}
-QRectF QGraphicsFrameEffect::boundingRect() const
+QRectF QGraphicsFrameEffect::boundingRectFor(const QRectF &rect) const
{
Q_D(const QGraphicsFrameEffect);
- if (!d->source)
- return QRectF();
- return d->source->boundingRect().adjusted(-d->width, -d->width, d->width, d->width);
+ return rect.adjusted(-d->width, -d->width, d->width, d->width);
}
-void QGraphicsFrameEffect::draw(QPainter *painter)
+void QGraphicsFrameEffect::draw(QPainter *painter, QGraphicsEffectSource *source)
{
Q_D(QGraphicsFrameEffect);
- if (!d->source)
- return;
-
- // Find the item's bounds in device coordinates.
- QTransform itemToPixmapTransform(painter->worldTransform());
- QRectF deviceBounds = itemToPixmapTransform.mapRect(d->source->boundingRect());
- if (deviceBounds.isEmpty())
- return;
-
- QRect frameRect = deviceBounds.adjusted(-d->width, -d->width, d->width, d->width)
- .toRect().adjusted(-1, -1, 1, 1);
-
- if (frameRect.x() != 0 || frameRect.y() != 0)
- itemToPixmapTransform *= QTransform::fromTranslate(-frameRect.x(), -frameRect.y());
-
- QPixmap pixmap(frameRect.size());
- if (!d->source->drawIntoPixmap(&pixmap, itemToPixmapTransform))
- return;
-
- painter->save();
- painter->setWorldTransform(QTransform());
-
painter->save();
painter->setOpacity(painter->opacity() * d->alpha);
painter->setPen(Qt::NoPen);
painter->setBrush(d->color);
- painter->drawRoundedRect(frameRect, 20, 20, Qt::RelativeSize);
+ painter->drawRoundedRect(boundingRect(), 20, 20, Qt::RelativeSize);
painter->restore();
- painter->drawPixmap(frameRect.topLeft(), pixmap);
-
- painter->restore();
+ source->draw(painter);
}
QGraphicsShadowEffect::QGraphicsShadowEffect()
@@ -627,83 +638,74 @@ QGraphicsShadowEffect::~QGraphicsShadowEffect()
{
}
-QPointF QGraphicsShadowEffect::shadowOffset() const
+QPointF QGraphicsShadowEffect::shadowOffset() const
{
Q_D(const QGraphicsShadowEffect);
return d->offset;
}
-void QGraphicsShadowEffect::setShadowOffset(const QPointF &ofs)
+void QGraphicsShadowEffect::setShadowOffset(const QPointF &ofs)
{
Q_D(QGraphicsShadowEffect);
d->offset = ofs;
+ updateBoundingRect();
}
-int QGraphicsShadowEffect::blurRadius() const
+int QGraphicsShadowEffect::blurRadius() const
{
Q_D(const QGraphicsShadowEffect);
return d->radius;
}
-void QGraphicsShadowEffect::setBlurRadius(int blurRadius)
+void QGraphicsShadowEffect::setBlurRadius(int blurRadius)
{
Q_D(QGraphicsShadowEffect);
d->radius = blurRadius;
+ updateBoundingRect();
}
-qreal QGraphicsShadowEffect::opacity() const
+qreal QGraphicsShadowEffect::opacity() const
{
Q_D(const QGraphicsShadowEffect);
return d->alpha;
}
-void QGraphicsShadowEffect::setOpacity(qreal opacity)
+void QGraphicsShadowEffect::setOpacity(qreal opacity)
{
Q_D(QGraphicsShadowEffect);
d->alpha = opacity;
}
-QRectF QGraphicsShadowEffect::boundingRect() const
+QRectF QGraphicsShadowEffect::boundingRectFor(const QRectF &rect) const
{
Q_D(const QGraphicsShadowEffect);
- if (!d->source)
- return QRectF();
- const QRectF srcBrect = d->source->boundingRect();
- QRectF shadowRect = srcBrect;
- shadowRect.adjust(d->offset.x(), d->offset.y(), d->offset.x(), d->offset.y());
+ QRectF shadowRect = rect.translated(d->offset);
QRectF blurRect = shadowRect;
qreal delta = d->radius * 3;
blurRect.adjust(-delta, -delta, delta, delta);
- QRectF totalRect = blurRect.united(srcBrect);
- return totalRect;
+ blurRect |= rect;
+ return blurRect;
}
-void QGraphicsShadowEffect::draw(QPainter *painter)
+void QGraphicsShadowEffect::draw(QPainter *painter, QGraphicsEffectSource *source)
{
Q_D(QGraphicsShadowEffect);
- if (!d->source)
- return;
-
- // Find the item's bounds in device coordinates.
- QTransform itemToPixmapTransform(painter->worldTransform());
- QRectF deviceBounds = itemToPixmapTransform.mapRect(d->source->boundingRect());
- QRect deviceRect = deviceBounds.toRect().adjusted(-1, -1, 1, 1);
- if (deviceRect.isEmpty())
- return;
-
- QRectF shadowRect = deviceBounds;
- shadowRect.adjust(d->offset.x(), d->offset.y(), d->offset.x(), d->offset.y());
+ const QRectF sourceRect = source->boundingRect(Qt::DeviceCoordinates);
+ const QRectF shadowRect = sourceRect.translated(d->offset);
QRectF blurRect = shadowRect;
qreal delta = d->radius * 3;
blurRect.adjust(-delta, -delta, delta, delta);
- QRect totalRect = blurRect.united(deviceRect).toRect().adjusted(-1, -1, 1, 1);
-
- if (totalRect.x() != 0 || totalRect.y() != 0)
- itemToPixmapTransform *= QTransform::fromTranslate(-totalRect.x(), -totalRect.y());
+ blurRect |= sourceRect;
+ const QRect effectRect = blurRect.toAlignedRect();
- QPixmap pixmap(totalRect.size());
- if (!d->source->drawIntoPixmap(&pixmap, itemToPixmapTransform))
- return;
+ QPixmap pixmap(effectRect.size());
+ pixmap.fill(Qt::transparent);
+ QPainter pixmapPainter(&pixmap);
+ pixmapPainter.setRenderHints(painter->renderHints());
+ pixmapPainter.setWorldTransform(painter->worldTransform());
+ pixmapPainter.translate(-effectRect.topLeft());
+ source->draw(&pixmapPainter);
+ pixmapPainter.end();
QImage img = pixmap.toImage();
QImage shadowImage(img.size(), QImage::Format_ARGB32);
@@ -714,21 +716,8 @@ void QGraphicsShadowEffect::draw(QPainter *painter)
// Draw using an untransformed painter.
QTransform restoreTransform = painter->worldTransform();
painter->setWorldTransform(QTransform());
-
- QRect shadowAlignedRect = shadowRect.toAlignedRect();
-
- qreal shadowx = blurRect.x() + delta;
- qreal shadowy = blurRect.y() + delta;
- if (blurRect.x() < deviceRect.x())
- shadowx = blurRect.x() + d->offset.x();
- if (blurRect.y() < deviceRect.y())
- shadowy = blurRect.y() + d->offset.y();
- painter->drawImage(shadowx, shadowy, shadowImage);
-
- qreal itemx = qMin(blurRect.x(), deviceBounds.x());
- qreal itemy = qMin(blurRect.y(), deviceBounds.y());
- painter->drawPixmap(itemx, itemy, pixmap);
-
+ painter->drawImage(effectRect.topLeft() + d->offset, shadowImage);
+ painter->drawPixmap(effectRect.topLeft(), pixmap);
painter->setWorldTransform(restoreTransform);
}
diff --git a/src/gui/graphicsview/qgraphicseffect.h b/src/gui/graphicsview/qgraphicseffect.h
index 74a8430..8cf80b9 100644
--- a/src/gui/graphicsview/qgraphicseffect.h
+++ b/src/gui/graphicsview/qgraphicseffect.h
@@ -43,18 +43,7 @@
#define QGRAPHICSEFFECT_H
#include <QtCore/qobject.h>
-#include <QtCore/qglobal.h>
#include <QtCore/qpoint.h>
-#include <QtCore/qvariant.h>
-#include <QtGui/qtransform.h>
-#include <QtGui/qcolor.h>
-
-QT_FORWARD_DECLARE_CLASS(QGraphicsItem);
-QT_FORWARD_DECLARE_CLASS(QStyleOptionGraphicsItem);
-QT_FORWARD_DECLARE_CLASS(QPainter);
-QT_FORWARD_DECLARE_CLASS(QPixmap);
-QT_FORWARD_DECLARE_CLASS(QWidget);
-QT_FORWARD_DECLARE_CLASS(QPixmapColorizeFilter);
QT_BEGIN_HEADER
@@ -64,28 +53,76 @@ QT_MODULE(Gui)
#if !defined(QT_NO_GRAPHICSVIEW) || (QT_EDITION & QT_MODULE_GRAPHICSVIEW) != QT_MODULE_GRAPHICSVIEW
+class QGraphicsItem;
+class QStyleOption;
+class QColor;
+class QPainter;
+class QRectF;
+class QPixmap;
+
+class QGraphicsEffectSourcePrivate;
+class Q_GUI_EXPORT QGraphicsEffectSource : public QObject
+{
+ Q_OBJECT
+public:
+ ~QGraphicsEffectSource();
+ const QGraphicsItem *graphicsItem() const;
+ const QStyleOption *styleOption() const;
+
+ bool isPixmap() const;
+ void draw(QPainter *painter);
+ void update();
+
+ QRectF boundingRect(Qt::CoordinateSystem coordinateSystem = Qt::LogicalCoordinates) const;
+ QPixmap pixmap(Qt::CoordinateSystem system = Qt::LogicalCoordinates, QPoint *offset = 0) const;
+
+protected:
+ QGraphicsEffectSource(QGraphicsEffectSourcePrivate &dd, QObject *parent = 0);
+
+private:
+ Q_DECLARE_PRIVATE(QGraphicsEffectSource);
+ Q_DISABLE_COPY(QGraphicsEffectSource);
+ friend class QGraphicsEffect;
+ friend class QGraphicsEffectPrivate;
+ friend class QGraphicsScenePrivate;
+ friend class QGraphicsItem;
+};
+
class QGraphicsEffectPrivate;
class Q_GUI_EXPORT QGraphicsEffect : public QObject
{
Q_OBJECT
+ Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled)
public:
QGraphicsEffect();
virtual ~QGraphicsEffect();
- virtual QRectF boundingRect() const;
+ virtual QRectF boundingRectFor(const QRectF &rect) const;
+ QRectF boundingRect() const;
+
+ void setSourcePixmap(const QPixmap &pixmap);
+ QPixmap sourcePixmap() const;
+ bool hasSourcePixmap() const;
+
+ QGraphicsEffectSource *source() const;
+
+ bool isEnabled() const;
+
+public Q_SLOTS:
+ void setEnabled(bool enable);
protected:
QGraphicsEffect(QGraphicsEffectPrivate &d);
- virtual void draw(QPainter *painter) = 0;
- void drawSource(QPainter *painter);
- bool drawSourceIntoPixmap(QPixmap *pixmap, const QTransform &xform = QTransform());
- QRectF sourceBoundingRect() const;
+ virtual void draw(QPainter *painter, QGraphicsEffectSource *source) = 0;
+ virtual void sourceChanged(QGraphicsEffectSource *newSource);
+ void updateBoundingRect();
private:
- friend class QGraphicsScenePrivate;
- friend class QGraphicsItem;
Q_DECLARE_PRIVATE(QGraphicsEffect)
Q_DISABLE_COPY(QGraphicsEffect)
+ friend class QGraphicsItem;
+ friend class QGraphicsItemPrivate;
+ friend class QGraphicsScenePrivate;
};
class QGraphicsGrayscaleEffectPrivate;
@@ -97,7 +134,7 @@ public:
~QGraphicsGrayscaleEffect();
protected:
- void draw(QPainter *painter);
+ void draw(QPainter *painter, QGraphicsEffectSource *source);
private:
Q_DECLARE_PRIVATE(QGraphicsGrayscaleEffect)
@@ -115,7 +152,7 @@ public:
void setColor(const QColor &c);
protected:
- void draw(QPainter *painter);
+ void draw(QPainter *painter, QGraphicsEffectSource *source);
private:
Q_DECLARE_PRIVATE(QGraphicsColorizeEffect)
@@ -133,7 +170,7 @@ public:
void setPixelSize(int pixelSize);
protected:
- void draw(QPainter *painter);
+ void draw(QPainter *painter, QGraphicsEffectSource *source);
private:
Q_DECLARE_PRIVATE(QGraphicsPixelizeEffect)
@@ -150,10 +187,9 @@ public:
int blurRadius() const;
void setBlurRadius(int blurRadius);
- QRectF boundingRect() const;
-
protected:
- void draw(QPainter *painter);
+ QRectF boundingRectFor(const QRectF &rect) const;
+ void draw(QPainter *painter, QGraphicsEffectSource *source);
private:
Q_DECLARE_PRIVATE(QGraphicsBlurEffect)
@@ -173,10 +209,9 @@ public:
qreal opacity() const;
void setOpacity(qreal opacity);
- QRectF boundingRect() const;
-
protected:
- void draw(QPainter *painter);
+ QRectF boundingRectFor(const QRectF &rect) const;
+ void draw(QPainter *painter, QGraphicsEffectSource *source);
private:
Q_DECLARE_PRIVATE(QGraphicsBloomEffect)
@@ -199,10 +234,9 @@ public:
qreal frameOpacity() const;
void setFrameOpacity(qreal opacity);
- QRectF boundingRect() const;
-
protected:
- void draw(QPainter *painter);
+ QRectF boundingRectFor(const QRectF &rect) const;
+ void draw(QPainter *painter, QGraphicsEffectSource *source);
private:
Q_DECLARE_PRIVATE(QGraphicsFrameEffect)
@@ -218,8 +252,10 @@ public:
QPointF shadowOffset() const;
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)); }
+ inline void setShadowOffset(qreal dx, qreal dy)
+ { setShadowOffset(QPointF(dx, dy)); }
+ inline void setShadowOffset(qreal d)
+ { setShadowOffset(QPointF(d, d)); }
int blurRadius() const;
void setBlurRadius(int blurRadius);
@@ -227,25 +263,15 @@ public:
qreal opacity() const;
void setOpacity(qreal opacity);
- QRectF boundingRect() const;
-
protected:
- void draw(QPainter *painter);
+ QRectF boundingRectFor(const QRectF &rect) const;
+ void draw(QPainter *painter, QGraphicsEffectSource *source);
private:
Q_DECLARE_PRIVATE(QGraphicsShadowEffect)
Q_DISABLE_COPY(QGraphicsShadowEffect)
};
-Q_DECLARE_METATYPE(QGraphicsEffect *)
-Q_DECLARE_METATYPE(QGraphicsGrayscaleEffect *)
-Q_DECLARE_METATYPE(QGraphicsColorizeEffect *)
-Q_DECLARE_METATYPE(QGraphicsPixelizeEffect *)
-Q_DECLARE_METATYPE(QGraphicsBlurEffect *)
-Q_DECLARE_METATYPE(QGraphicsBloomEffect *)
-Q_DECLARE_METATYPE(QGraphicsFrameEffect *)
-Q_DECLARE_METATYPE(QGraphicsShadowEffect *)
-
#endif // QT_NO_GRAPHICSVIEW
QT_END_NAMESPACE
diff --git a/src/gui/graphicsview/qgraphicseffect_p.h b/src/gui/graphicsview/qgraphicseffect_p.h
index 37bcfdf..5348ae9 100644
--- a/src/gui/graphicsview/qgraphicseffect_p.h
+++ b/src/gui/graphicsview/qgraphicseffect_p.h
@@ -54,38 +54,59 @@
//
#include "qgraphicseffect.h"
+
+#if !defined(QT_NO_GRAPHICSVIEW) || (QT_EDITION & QT_MODULE_GRAPHICSVIEW) != QT_MODULE_GRAPHICSVIEW
+
#include <private/qobject_p.h>
#include <private/qpixmapfilter_p.h>
-#if !defined(QT_NO_GRAPHICSVIEW) || (QT_EDITION & QT_MODULE_GRAPHICSVIEW) != QT_MODULE_GRAPHICSVIEW
+#include <QtCore/qrect.h>
+#include <QtCore/qpoint.h>
+#include <QtGui/qcolor.h>
QT_BEGIN_NAMESPACE
-class Q_GUI_EXPORT QGraphicsEffectSource
+class QGraphicsEffectSourcePrivate : public QObjectPrivate
{
+ Q_DECLARE_PUBLIC(QGraphicsEffectSource)
public:
- QGraphicsEffectSource() {}
- virtual ~QGraphicsEffectSource() {}
+ QGraphicsEffectSourcePrivate() : QObjectPrivate() {}
+ virtual ~QGraphicsEffectSourcePrivate() {}
virtual void detach() = 0;
- virtual QRectF boundingRect() = 0;
+ virtual QRectF boundingRect(Qt::CoordinateSystem system) const = 0;
+ virtual const QGraphicsItem *graphicsItem() const = 0;
+ virtual const QStyleOption *styleOption() const = 0;
virtual void draw(QPainter *p) = 0;
- virtual bool drawIntoPixmap(QPixmap *, const QTransform & = QTransform()) = 0;
+ virtual void update() = 0;
+ virtual bool isPixmap() const = 0;
+ virtual QPixmap pixmap(Qt::CoordinateSystem system, QPoint *offset = 0) const = 0;
+ friend class QGraphicsScenePrivate;
+ friend class QGraphicsItem;
+ friend class QGraphicsItemPrivate;
};
class Q_GUI_EXPORT QGraphicsEffectPrivate : public QObjectPrivate
{
Q_DECLARE_PUBLIC(QGraphicsEffect)
public:
- QGraphicsEffectPrivate() : source(0) {}
- QGraphicsEffectSource *source;
+ QGraphicsEffectPrivate() : source(0), hasSourcePixmap(0), isEnabled(1) {}
+
inline void setGraphicsEffectSource(QGraphicsEffectSource *newSource)
{
if (source) {
- source->detach();
+ source->d_func()->detach();
delete source;
}
source = newSource;
+ q_func()->sourceChanged(newSource);
}
+
+ QGraphicsEffectSource *source;
+ QRectF boundingRect;
+ QPixmap sourcePixmap;
+ quint32 hasSourcePixmap : 1;
+ quint32 isEnabled : 1;
+ quint32 padding : 30; // feel free to use
};
class QGraphicsGrayscaleEffectPrivate : public QGraphicsEffectPrivate
@@ -157,7 +178,7 @@ class QGraphicsShadowEffectPrivate : public QGraphicsEffectPrivate
{
Q_DECLARE_PUBLIC(QGraphicsShadowEffect)
public:
- QGraphicsShadowEffectPrivate() : offset(4,4), radius(8), alpha(0.7) {}
+ QGraphicsShadowEffectPrivate() : offset(4, 4), radius(8), alpha(0.7) {}
QPointF offset;
int radius;
diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp
index 7533fa4..5178d80 100644
--- a/src/gui/graphicsview/qgraphicsitem.cpp
+++ b/src/gui/graphicsview/qgraphicsitem.cpp
@@ -2231,7 +2231,9 @@ void QGraphicsItem::setGraphicsEffect(QGraphicsEffect *effect)
oldEffectPrivate->setGraphicsEffectSource(0); // deletes the current source.
} else {
// Set new effect.
- effect->d_func()->setGraphicsEffectSource(new QGraphicsItemEffectSource(this));
+ QGraphicsEffectSourcePrivate *sourced = new QGraphicsItemEffectSourcePrivate(this);
+ QGraphicsEffectSource *source = new QGraphicsEffectSource(*sourced);
+ effect->d_func()->setGraphicsEffectSource(source);
d_ptr->graphicsEffect = effect;
}
@@ -2250,7 +2252,7 @@ void QGraphicsItem::setGraphicsEffect(QGraphicsEffect *effect)
*/
QRectF QGraphicsItem::effectiveBoundingRect() const
{
- if (d_ptr->graphicsEffect)
+ if (d_ptr->graphicsEffect && d_ptr->graphicsEffect->isEnabled())
return d_ptr->graphicsEffect->boundingRect();
return boundingRect();
}
@@ -9990,6 +9992,88 @@ int QGraphicsItemGroup::type() const
return Type;
}
+QRectF QGraphicsItemEffectSourcePrivate::boundingRect(Qt::CoordinateSystem system) const
+{
+ QRectF rect = item->boundingRect();
+ rect |= item->childrenBoundingRect();
+ if (info && system == Qt::DeviceCoordinates) {
+ Q_ASSERT(info->transformPtr);
+ return info->transformPtr->mapRect(rect);
+ }
+ return rect;
+}
+
+void QGraphicsItemEffectSourcePrivate::draw(QPainter *painter)
+{
+ if (!info) {
+ qWarning("QGraphicsEffectSource::draw: Can only begin as a result of QGraphicsEffect::draw");
+ return;
+ }
+
+ if (painter == info->painter) {
+ QGraphicsScenePrivate *scened = item->d_ptr->scene->d_func();
+ scened->draw(item, painter, info->viewTransform, info->transformPtr, info->exposedRegion,
+ info->widget, info->opacity, 0, info->wasDirtySceneTransform,
+ info->drawItem);
+ } else {
+ QTransform effectTransform = painter->worldTransform();
+ effectTransform *= info->transformPtr->inverted();
+ QGraphicsScenePrivate *scened = item->d_ptr->scene->d_func();
+ scened->draw(item, painter, info->viewTransform, info->transformPtr, info->exposedRegion,
+ info->widget, info->opacity, &effectTransform, info->wasDirtySceneTransform,
+ info->drawItem);
+ }
+}
+
+QPixmap QGraphicsItemEffectSourcePrivate::pixmap(Qt::CoordinateSystem system, QPoint *offset) const
+{
+ const bool deviceCoordinates = (system == Qt::DeviceCoordinates);
+ if (!info && deviceCoordinates) {
+ // Device coordinates without info not yet supported.
+ qWarning("QGraphicsEffectSource::pixmap: Not yet implemented, lacking device context");
+ return QPixmap();
+ }
+
+ const QRectF sourceRect = boundingRect(system);
+ const QRect effectRect = item->graphicsEffect()->boundingRectFor(sourceRect).toAlignedRect();
+ if (offset)
+ *offset = sourceRect.toAlignedRect().topLeft();
+
+ QPixmap pixmap(effectRect.size());
+ pixmap.fill(Qt::transparent);
+ QPainter pixmapPainter(&pixmap);
+ pixmapPainter.setRenderHints(info ? info->painter->renderHints() : QPainter::TextAntialiasing);
+
+ const QTransform translateTransform = QTransform::fromTranslate(-effectRect.x(),
+ -effectRect.y());
+ if (!info) {
+ // Logical coordinates without info.
+ QTransform sceneTransform = item->sceneTransform();
+ QTransform effectTransform = sceneTransform.inverted();
+ effectTransform *= translateTransform;
+
+ QGraphicsScenePrivate *scened = item->d_ptr->scene->d_func();
+ scened->draw(item, &pixmapPainter, 0, &sceneTransform, 0, 0, qreal(1.0),
+ &effectTransform, false, true);
+ } else if (deviceCoordinates) {
+ // Device coordinates with info.
+ QGraphicsScenePrivate *scened = item->d_ptr->scene->d_func();
+ scened->draw(item, &pixmapPainter, info->viewTransform, info->transformPtr, info->exposedRegion,
+ info->widget, info->opacity, &translateTransform, info->wasDirtySceneTransform,
+ info->drawItem);
+ } else {
+ // Item coordinates with info.
+ QTransform effectTransform = info->transformPtr->inverted();
+ effectTransform *= translateTransform;
+
+ QGraphicsScenePrivate *scened = item->d_ptr->scene->d_func();
+ scened->draw(item, &pixmapPainter, info->viewTransform, info->transformPtr, info->exposedRegion,
+ info->widget, info->opacity, &effectTransform, info->wasDirtySceneTransform,
+ info->drawItem);
+ }
+ return pixmap;
+}
+
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug debug, QGraphicsItem *item)
{
diff --git a/src/gui/graphicsview/qgraphicsitem.h b/src/gui/graphicsview/qgraphicsitem.h
index 1bcf0e0..afbaf24 100644
--- a/src/gui/graphicsview/qgraphicsitem.h
+++ b/src/gui/graphicsview/qgraphicsitem.h
@@ -460,6 +460,7 @@ private:
friend class QGraphicsSceneIndexPrivate;
friend class QGraphicsSceneBspTreeIndex;
friend class QGraphicsSceneBspTreeIndexPrivate;
+ friend class QGraphicsItemEffectSourcePrivate;
friend class ::tst_QGraphicsItem;
friend bool qt_closestLeaf(const QGraphicsItem *, const QGraphicsItem *);
friend bool qt_closestItemFirst(const QGraphicsItem *, const QGraphicsItem *);
diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h
index 1fedca8..69d8b5f 100644
--- a/src/gui/graphicsview/qgraphicsitem_p.h
+++ b/src/gui/graphicsview/qgraphicsitem_p.h
@@ -512,44 +512,60 @@ struct QGraphicsItemPrivate::TransformData {
}
};
-class QGraphicsItemEffectSource : public QGraphicsEffectSource
+struct QGraphicsItemPaintInfo
+{
+ inline QGraphicsItemPaintInfo(const QTransform *const xform1, QTransform *xform2,
+ QRegion *r, QWidget *w, QStyleOptionGraphicsItem *opt,
+ QPainter *p, qreal o, bool b1, bool b2)
+ : viewTransform(xform1), transformPtr(xform2), exposedRegion(r), widget(w),
+ option(opt), painter(p), opacity(o), wasDirtySceneTransform(b1), drawItem(b2)
+ {}
+
+ const QTransform *viewTransform;
+ QTransform *transformPtr;
+ QRegion *exposedRegion;
+ QWidget *widget;
+ QStyleOptionGraphicsItem *option;
+ QPainter *painter;
+ qreal opacity;
+ quint32 wasDirtySceneTransform : 1;
+ quint32 drawItem : 1;
+};
+
+class QGraphicsItemEffectSourcePrivate : public QGraphicsEffectSourcePrivate
{
public:
- QGraphicsItemEffectSource(QGraphicsItem *i)
- : QGraphicsEffectSource(), item(i), option(0), widget(0)
+ QGraphicsItemEffectSourcePrivate(QGraphicsItem *i)
+ : QGraphicsEffectSourcePrivate(), item(i), info(0)
{}
inline void detach()
{ item->setGraphicsEffect(0); }
- inline QRectF boundingRect()
- { return item->boundingRect(); }
+ inline const QGraphicsItem *graphicsItem() const
+ { return item; }
- inline void draw(QPainter *painter)
- { item->paint(painter, option, widget); }
+ inline void update()
+ { item->update(); }
- inline bool drawIntoPixmap(QPixmap *pixmap, const QTransform &itemToPixmapTransform)
+ inline bool isPixmap() const
{
- pixmap->fill(Qt::transparent);
- QPainter pixmapPainter(pixmap);
- if (!itemToPixmapTransform.isIdentity())
- pixmapPainter.setWorldTransform(itemToPixmapTransform);
- item->paint(&pixmapPainter, option, widget);
- return true;
+ return (item->type() == QGraphicsPixmapItem::Type);
+ //|| (item->d_ptr->isObject && qobject_cast<QFxImage *>(q_func()));
}
- inline void setPaintInfo(const QStyleOptionGraphicsItem *o, QWidget *w)
- { option = o; widget = w; }
+ inline const QStyleOption *styleOption() const
+ { return info ? info->option : 0; }
- void resetPaintInfo()
- { option = 0; widget = 0; }
+ QRectF boundingRect(Qt::CoordinateSystem system) const;
+ void draw(QPainter *);
+ QPixmap pixmap(Qt::CoordinateSystem system, QPoint *offset) const;
-private:
QGraphicsItem *item;
- const QStyleOptionGraphicsItem *option;
- QWidget *widget;
+ QGraphicsItemPaintInfo *info;
};
+
/*!
\internal
*/
diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp
index 41bcb76..5cd0ab2 100644
--- a/src/gui/graphicsview/qgraphicsscene.cpp
+++ b/src/gui/graphicsview/qgraphicsscene.cpp
@@ -208,7 +208,7 @@
#ifndef QT_NO_GRAPHICSVIEW
-#include "qgraphicseffect.h"
+#include "qgraphicseffect_p.h"
#include "qgraphicsitem.h"
#include "qgraphicsitem_p.h"
#include "qgraphicslayout.h"
@@ -3963,19 +3963,6 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte
QGraphicsItemPrivate *itemd = item->d_ptr;
QGraphicsItem::CacheMode cacheMode = QGraphicsItem::CacheMode(itemd->cacheMode);
- bool noCache = cacheMode == QGraphicsItem::NoCache ||
-#ifdef Q_WS_X11
- !X11->use_xrender;
-#else
- false;
-#endif
-
- // Render using effect, works now only for no cache mode
- if (noCache && itemd->graphicsEffect) {
- itemd->graphicsEffect->draw(painter);
- return;
- }
-
// Render directly, using no cache.
if (cacheMode == QGraphicsItem::NoCache
#ifdef Q_WS_X11
@@ -4288,7 +4275,7 @@ void QGraphicsScenePrivate::drawItems(QPainter *painter, const QTransform *const
void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter *painter,
const QTransform *const viewTransform,
QRegion *exposedRegion, QWidget *widget,
- qreal parentOpacity)
+ qreal parentOpacity, const QTransform *const effectTransform)
{
Q_ASSERT(item);
@@ -4341,7 +4328,8 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter *
ENSURE_TRANSFORM_PTR
QRect viewBoundingRect = translateOnlyTransform ? brect.translated(transformPtr->dx(), transformPtr->dy()).toRect()
: transformPtr->mapRect(brect).toRect();
- item->d_ptr->paintedViewBoundingRects.insert(widget, viewBoundingRect);
+ if (widget)
+ item->d_ptr->paintedViewBoundingRects.insert(widget, viewBoundingRect);
viewBoundingRect.adjust(-1, -1, 1, 1);
drawItem = exposedRegion ? exposedRegion->intersects(viewBoundingRect) : !viewBoundingRect.isEmpty();
if (!drawItem) {
@@ -4355,13 +4343,44 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter *
}
} // else we know for sure this item has children we must process.
+ if (itemHasChildren && itemClipsChildrenToShape)
+ ENSURE_TRANSFORM_PTR;
+
+ if (item->d_ptr->graphicsEffect && item->d_ptr->graphicsEffect->isEnabled()) {
+ ENSURE_TRANSFORM_PTR;
+ QGraphicsItemPaintInfo info(viewTransform, transformPtr, exposedRegion, widget, &styleOptionTmp,
+ painter, opacity, wasDirtyParentSceneTransform, drawItem);
+ QGraphicsEffectSource *source = item->d_ptr->graphicsEffect->d_func()->source;
+ QGraphicsItemEffectSourcePrivate *sourced = static_cast<QGraphicsItemEffectSourcePrivate *>
+ (source->d_func());
+ sourced->info = &info;
+ const QTransform restoreTransform = painter->worldTransform();
+ painter->setWorldTransform(*transformPtr);
+ item->d_ptr->graphicsEffect->draw(painter, source);
+ painter->setWorldTransform(restoreTransform);
+ } else {
+ draw(item, painter, viewTransform, transformPtr, exposedRegion, widget, opacity,
+ effectTransform, wasDirtyParentSceneTransform, drawItem);
+ }
+}
+
+void QGraphicsScenePrivate::draw(QGraphicsItem *item, QPainter *painter, const QTransform *const viewTransform,
+ QTransform *transformPtr, QRegion *exposedRegion, QWidget *widget, qreal opacity,
+ const QTransform *effectTransform, bool wasDirtyParentSceneTransform, bool drawItem)
+{
+ const bool itemIsFullyTransparent = (opacity < 0.0001);
+ const bool itemClipsChildrenToShape = (item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape);
+ const bool itemHasChildren = !item->d_ptr->children.isEmpty();
+
int i = 0;
if (itemHasChildren) {
item->d_ptr->ensureSortedChildren();
if (itemClipsChildrenToShape) {
painter->save();
- ENSURE_TRANSFORM_PTR
+ Q_ASSERT(transformPtr);
+ if (effectTransform)
+ *transformPtr *= *effectTransform;
painter->setWorldTransform(*transformPtr);
painter->setClipPath(item->shape(), Qt::IntersectClip);
}
@@ -4375,15 +4394,15 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter *
break;
if (itemIsFullyTransparent && !(child->d_ptr->flags & QGraphicsItem::ItemIgnoresParentOpacity))
continue;
- drawSubtreeRecursive(child, painter, viewTransform, exposedRegion, widget, opacity);
+ drawSubtreeRecursive(child, painter, viewTransform, exposedRegion, widget, opacity, effectTransform);
}
}
// Draw item
if (drawItem) {
Q_ASSERT(!itemIsFullyTransparent);
- Q_ASSERT(itemHasContents);
- ENSURE_TRANSFORM_PTR
+ Q_ASSERT(!(item->d_ptr->flags & QGraphicsItem::ItemHasNoContents));
+ Q_ASSERT(transformPtr);
item->d_ptr->initStyleOption(&styleOptionTmp, *transformPtr, exposedRegion
? *exposedRegion : QRegion(), exposedRegion == 0);
@@ -4392,28 +4411,21 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter *
if (savePainter)
painter->save();
- if (!itemHasChildren || !itemClipsChildrenToShape)
+ if (!itemHasChildren || !itemClipsChildrenToShape) {
+ if (effectTransform)
+ *transformPtr *= *effectTransform;
painter->setWorldTransform(*transformPtr);
+ }
if (itemClipsToShape)
painter->setClipPath(item->shape(), Qt::IntersectClip);
painter->setOpacity(opacity);
- QGraphicsItemEffectSource *source = item->d_ptr->graphicsEffect
- ? static_cast<QGraphicsItemEffectSource *>
- (item->d_ptr->graphicsEffect->d_func()->source)
- : 0;
- if (source)
- source->setPaintInfo(&styleOptionTmp, widget);
-
- if (!item->d_ptr->cacheMode && !item->d_ptr->isWidget && !source)
+ if (!item->d_ptr->cacheMode && !item->d_ptr->isWidget)
item->paint(painter, &styleOptionTmp, widget);
else
drawItemHelper(item, painter, &styleOptionTmp, widget, painterStateProtection);
- if (source)
- source->resetPaintInfo();
-
if (savePainter)
painter->restore();
}
@@ -4426,7 +4438,7 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter *
child->d_ptr->dirtySceneTransform = 1;
if (itemIsFullyTransparent && !(child->d_ptr->flags & QGraphicsItem::ItemIgnoresParentOpacity))
continue;
- drawSubtreeRecursive(child, painter, viewTransform, exposedRegion, widget, opacity);
+ drawSubtreeRecursive(child, painter, viewTransform, exposedRegion, widget, opacity, effectTransform);
}
}
@@ -4509,8 +4521,12 @@ void QGraphicsScenePrivate::markDirty(QGraphicsItem *item, const QRectF &rect, b
item->d_ptr->ignoreOpacity = 1;
QGraphicsItem *p = item->d_ptr->parent;
- while (p && !p->d_ptr->dirtyChildren) {
+ while (p) {
p->d_ptr->dirtyChildren = 1;
+ if (p->d_ptr->graphicsEffect && p->d_ptr->graphicsEffect->isEnabled()) {
+ p->d_ptr->dirty = 1;
+ p->d_ptr->fullUpdatePending = 1;
+ }
p = p->d_ptr->parent;
}
}
@@ -4619,7 +4635,7 @@ void QGraphicsScenePrivate::processDirtyItemsRecursive(QGraphicsItem *item, bool
// Process item.
if (item->d_ptr->dirty || item->d_ptr->paintedViewBoundingRectsNeedRepaint) {
const bool useCompatUpdate = views.isEmpty() || (connectedSignals & changedSignalMask);
- const QRectF itemBoundingRect = adjustedItemBoundingRect(item);
+ const QRectF itemBoundingRect = adjustedItemEffectiveBoundingRect(item);
if (useCompatUpdate && !itemIsUntransformable && qFuzzyIsNull(item->boundingRegionGranularity())) {
// This block of code is kept for compatibility. Since 4.5, by default
diff --git a/src/gui/graphicsview/qgraphicsscene.h b/src/gui/graphicsview/qgraphicsscene.h
index 89436aa..67a2983 100644
--- a/src/gui/graphicsview/qgraphicsscene.h
+++ b/src/gui/graphicsview/qgraphicsscene.h
@@ -307,6 +307,7 @@ private:
friend class QGraphicsSceneIndexPrivate;
friend class QGraphicsSceneBspTreeIndex;
friend class QGraphicsSceneBspTreeIndexPrivate;
+ friend class QGraphicsItemEffectSourcePrivate;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QGraphicsScene::SceneLayers)
diff --git a/src/gui/graphicsview/qgraphicsscene_p.h b/src/gui/graphicsview/qgraphicsscene_p.h
index 7e95f70..56e6224 100644
--- a/src/gui/graphicsview/qgraphicsscene_p.h
+++ b/src/gui/graphicsview/qgraphicsscene_p.h
@@ -202,7 +202,11 @@ public:
QRegion *exposedRegion, QWidget *widget);
void drawSubtreeRecursive(QGraphicsItem *item, QPainter *painter, const QTransform *const,
- QRegion *exposedRegion, QWidget *widget, qreal parentOpacity = qreal(1.0));
+ QRegion *exposedRegion, QWidget *widget, qreal parentOpacity = qreal(1.0),
+ const QTransform *const effectTransform = 0);
+ void draw(QGraphicsItem *, QPainter *, const QTransform *const, QTransform *,
+ QRegion *, QWidget *, qreal, const QTransform *const, bool, bool);
+
void markDirty(QGraphicsItem *item, const QRectF &rect = QRectF(), bool invalidateChildren = false,
bool maybeDirtyClipPath = false, bool force = false, bool ignoreOpacity = false,
bool removingItemFromScene = false);
diff --git a/src/opengl/qgraphicsshadereffect.cpp b/src/opengl/qgraphicsshadereffect.cpp
index d4f5fa0..e8d9ae3 100644
--- a/src/opengl/qgraphicsshadereffect.cpp
+++ b/src/opengl/qgraphicsshadereffect.cpp
@@ -246,25 +246,11 @@ void QGraphicsShaderEffect::setPixelShaderFragment(const QByteArray& code)
/*!
\reimp
*/
-void QGraphicsShaderEffect::draw(QPainter *painter)
+void QGraphicsShaderEffect::draw(QPainter *painter, QGraphicsEffectSource *source)
{
Q_D(QGraphicsShaderEffect);
#ifdef QGL_HAVE_CUSTOM_SHADERS
- // Find the item's bounds in device coordinates.
- QTransform itemToPixmapTransform(painter->worldTransform());
- QRectF deviceBounds = itemToPixmapTransform.mapRect(sourceBoundingRect());
- QRect deviceRect = deviceBounds.toRect().adjusted(-1, -1, 1, 1);
- if (deviceRect.isEmpty())
- return;
-
- if (deviceRect.x() != 0 || deviceRect.y() != 0)
- itemToPixmapTransform *= QTransform::fromTranslate(-deviceRect.x(), -deviceRect.y());
-
- QPixmap pixmap(deviceRect.size());
- if (!d->source->drawIntoPixmap(&pixmap, itemToPixmapTransform))
- return;
-
// Set the custom shader on the paint engine. The setOnPainter()
// call may fail if the paint engine is not GL2. In that case,
// we fall through to drawing the pixmap normally.
@@ -274,17 +260,25 @@ void QGraphicsShaderEffect::draw(QPainter *painter)
}
bool usingShader = d->customShaderStage->setOnPainter(painter);
- // Draw using an untransformed painter.
- QTransform restoreTransform = painter->worldTransform();
- painter->setWorldTransform(QTransform());
- painter->drawPixmap(deviceRect.topLeft(), pixmap);
- painter->setWorldTransform(restoreTransform);
+ 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);
+ painter->drawPixmap(offset, pixmap);
+ } else {
+ // 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->drawPixmap(offset, pixmap);
+ painter->setWorldTransform(restoreTransform);
+ }
// Remove the custom shader to return to normal painting operations.
if (usingShader)
d->customShaderStage->removeFromPainter(painter);
#else
- drawSource(painter);
+ source->draw(painter);
#endif
}
diff --git a/src/opengl/qgraphicsshadereffect.h b/src/opengl/qgraphicsshadereffect.h
index 032a233..d9f2d4f 100644
--- a/src/opengl/qgraphicsshadereffect.h
+++ b/src/opengl/qgraphicsshadereffect.h
@@ -67,7 +67,7 @@ public:
void setPixelShaderFragment(const QByteArray& code);
protected:
- void draw(QPainter *painter);
+ void draw(QPainter *painter, QGraphicsEffectSource *source);
void setUniformsDirty();
virtual void setUniforms(QGLShaderProgram *program);