diff options
-rw-r--r-- | examples/graphicsview/blurpicker/blureffect.cpp | 4 | ||||
-rw-r--r-- | examples/graphicsview/blurpicker/blureffect.h | 2 | ||||
-rw-r--r-- | examples/graphicsview/lighting/shadoweffect.cpp | 8 | ||||
-rw-r--r-- | examples/graphicsview/lighting/shadoweffect.h | 4 | ||||
-rw-r--r-- | src/corelib/global/qnamespace.h | 5 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicseffect.cpp | 409 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicseffect.h | 114 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicseffect_p.h | 41 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsitem.cpp | 88 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsitem.h | 1 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsitem_p.h | 58 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsscene.cpp | 86 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsscene.h | 1 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsscene_p.h | 6 | ||||
-rw-r--r-- | src/opengl/qgraphicsshadereffect.cpp | 36 | ||||
-rw-r--r-- | src/opengl/qgraphicsshadereffect.h | 2 |
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); |