src/gui/effects/qgraphicseffect.cpp
changeset 3 41300fa6a67c
parent 0 1918ee327afb
child 4 3b1da2848fc7
child 7 f7bc934e204c
equal deleted inserted replaced
2:56cd8111b7f7 3:41300fa6a67c
    63     \list
    63     \list
    64     \o QGraphicsBlurEffect - blurs the item by a given radius
    64     \o QGraphicsBlurEffect - blurs the item by a given radius
    65     \o QGraphicsDropShadowEffect - renders a dropshadow behind the item
    65     \o QGraphicsDropShadowEffect - renders a dropshadow behind the item
    66     \o QGraphicsColorizeEffect - renders the item in shades of any given color
    66     \o QGraphicsColorizeEffect - renders the item in shades of any given color
    67     \o QGraphicsOpacityEffect - renders the item with an opacity
    67     \o QGraphicsOpacityEffect - renders the item with an opacity
    68     \o QGraphicsPixelizeEffect - pixelizes the item with any pixel size
       
    69     \o QGraphicsGrayscaleEffect - renders the item in shades of gray
       
    70     \o QGraphicsBloomEffect - applies a blooming / glowing effect
       
    71     \endlist
    68     \endlist
    72 
    69 
    73     \img graphicseffect-effects.png
    70     \table
       
    71     \row
       
    72     \o{2,1} \img graphicseffect-plain.png
       
    73     \row
       
    74     \o \img graphicseffect-blur.png
       
    75     \o \img graphicseffect-colorize.png
       
    76     \row
       
    77     \o \img graphicseffect-opacity.png
       
    78     \o \img graphicseffect-drop-shadow.png
       
    79     \endtable
       
    80 
    74     \img graphicseffect-widget.png
    81     \img graphicseffect-widget.png
    75 
    82 
    76     For more information on how to use each effect, refer to the specific
    83     For more information on how to use each effect, refer to the specific
    77     effect's documentation.
    84     effect's documentation.
    78 
    85 
    79     To create your own custom effect, create a subclass of QGraphicsEffect (or
    86     To create your own custom effect, create a subclass of QGraphicsEffect (or
    80     any other existing effects) and reimplement the virtual function draw().
    87     any other existing effects) and reimplement the virtual function draw().
    81     This function is called whenever the effect needs to redraw. The draw()
    88     This function is called whenever the effect needs to redraw. The draw()
    82     function accepts two arguments: the painter and a pointer to the source
    89     function takes the painter with which to draw as an argument. For more
    83     (QGraphicsEffectSource). The source provides extra context information,
    90     information, refer to the documenation for draw(). In the draw() function
    84     such as a pointer to the item that is rendering the effect, any cached
    91     you can call sourcePixmap() to get a pixmap of the graphics effect source
    85     pixmap data, or the device rectangle bounds. For more information, refer to
    92     which you can then process.
    86     the documenation for draw(). To obtain a pointer to the current source,
       
    87     simply call source().
       
    88 
    93 
    89     If your effect changes, use update() to request for a redraw. If your
    94     If your effect changes, use update() to request for a redraw. If your
    90     custom effect changes the bounding rectangle of the source, e.g., a radial
    95     custom effect changes the bounding rectangle of the source, e.g., a radial
    91     glow effect may need to apply an extra margin, you can reimplement the
    96     glow effect may need to apply an extra margin, you can reimplement the
    92     virtual boundingRectFor() function, and call updateBoundingRect() to notify
    97     virtual boundingRectFor() function, and call updateBoundingRect()
    93     the framework whenever this rectangle changes. The virtual
    98     to notify the framework whenever this rectangle changes. The virtual
    94     sourceBoundingRectChanged() function is called to notify the effects that
    99     sourceChanged() function is called to notify the effects that
    95     the source's bounding rectangle has changed - e.g., if the source is a
   100     the source has changed in some way - e.g., if the source is a
    96     QGraphicsRectItem and its rectangle parameters have changed.
   101     QGraphicsRectItem and its rectangle parameters have changed.
    97 
   102 
    98     \sa QGraphicsItem::setGraphicsEffect(), QWidget::setGraphicsEffect(),
   103     \sa QGraphicsItem::setGraphicsEffect(), QWidget::setGraphicsEffect()
    99     QGraphicsEffectSource
       
   100 */
   104 */
   101 
   105 
   102 #include "qgraphicseffect_p.h"
   106 #include "qgraphicseffect_p.h"
       
   107 #include "private/qgraphicsitem_p.h"
       
   108 
       
   109 #include <QtGui/qgraphicsitem.h>
   103 
   110 
   104 #include <QtGui/qimage.h>
   111 #include <QtGui/qimage.h>
   105 #include <QtGui/qpainter.h>
   112 #include <QtGui/qpainter.h>
       
   113 #include <QtGui/qpaintengine.h>
   106 #include <QtCore/qrect.h>
   114 #include <QtCore/qrect.h>
   107 #include <QtCore/qdebug.h>
   115 #include <QtCore/qdebug.h>
   108 #include <private/qdrawhelper_p.h>
   116 #include <private/qdrawhelper_p.h>
   109 
   117 
       
   118 #ifndef QT_NO_GRAPHICSEFFECT
   110 QT_BEGIN_NAMESPACE
   119 QT_BEGIN_NAMESPACE
   111 
   120 
   112 /*!
   121 /*!
       
   122     \internal
   113     \class QGraphicsEffectSource
   123     \class QGraphicsEffectSource
   114     \brief The QGraphicsEffectSource class represents the source on which a
   124     \brief The QGraphicsEffectSource class represents the source on which a
   115            QGraphicsEffect is installed on.
   125            QGraphicsEffect is installed on.
   116     \since 4.6
       
   117 
   126 
   118     When a QGraphicsEffect is installed on a QGraphicsItem, for example, this
   127     When a QGraphicsEffect is installed on a QGraphicsItem, for example, this
   119     class will act as a wrapper around QGraphicsItem. Then, calling update() is
   128     class will act as a wrapper around QGraphicsItem. Then, calling update() is
   120     effectively the same as calling QGraphicsItem::update().
   129     effectively the same as calling QGraphicsItem::update().
   121 
   130 
   137 */
   146 */
   138 QGraphicsEffectSource::~QGraphicsEffectSource()
   147 QGraphicsEffectSource::~QGraphicsEffectSource()
   139 {}
   148 {}
   140 
   149 
   141 /*!
   150 /*!
   142     Returns the bounds of the current painter's device.
       
   143 
       
   144     This function is useful when you want to draw something in device
       
   145     coordinates and ensure the size of the pixmap is not bigger than the size
       
   146     of the device.
       
   147 
       
   148     Calling QGraphicsEffectSource::pixmap(Qt::DeviceCoordinates) always returns
       
   149     a pixmap which is bound to the device's size.
       
   150 
       
   151     \sa pixmap()
       
   152 */
       
   153 QRect QGraphicsEffectSource::deviceRect() const
       
   154 {
       
   155     return d_func()->deviceRect();
       
   156 }
       
   157 
       
   158 /*!
       
   159     Returns the bounding rectangle of the source mapped to the given \a system.
   151     Returns the bounding rectangle of the source mapped to the given \a system.
   160 
   152 
   161     \sa draw()
   153     \sa draw()
   162 */
   154 */
   163 QRectF QGraphicsEffectSource::boundingRect(Qt::CoordinateSystem system) const
   155 QRectF QGraphicsEffectSource::boundingRect(Qt::CoordinateSystem system) const
   164 {
   156 {
   165     return d_func()->boundingRect(system);
   157     return d_func()->boundingRect(system);
       
   158 }
       
   159 
       
   160 /*!
       
   161     Returns the bounding rectangle of the source mapped to the given \a system.
       
   162 
       
   163     Calling this function with Qt::DeviceCoordinates outside of
       
   164     QGraphicsEffect::draw() will give undefined results, as there is no device
       
   165     context available.
       
   166 
       
   167     \sa draw()
       
   168 */
       
   169 QRectF QGraphicsEffect::sourceBoundingRect(Qt::CoordinateSystem system) const
       
   170 {
       
   171     Q_D(const QGraphicsEffect);
       
   172     if (d->source)
       
   173         return d->source->boundingRect(system);
       
   174     return QRectF();
   166 }
   175 }
   167 
   176 
   168 /*!
   177 /*!
   169     Returns a pointer to the item if this source is a QGraphicsItem; otherwise
   178     Returns a pointer to the item if this source is a QGraphicsItem; otherwise
   170     returns 0.
   179     returns 0.
   201 /*!
   210 /*!
   202     Draws the source using the given \a painter.
   211     Draws the source using the given \a painter.
   203 
   212 
   204     This function should only be called from QGraphicsEffect::draw().
   213     This function should only be called from QGraphicsEffect::draw().
   205 
   214 
       
   215     \sa QGraphicsEffect::draw()
       
   216 */
       
   217 void QGraphicsEffectSource::draw(QPainter *painter)
       
   218 {
       
   219     Q_D(const QGraphicsEffectSource);
       
   220 
       
   221     QPixmap pm;
       
   222     if (QPixmapCache::find(d->m_cacheKey, &pm)) {
       
   223         QTransform restoreTransform;
       
   224         if (d->m_cachedSystem == Qt::DeviceCoordinates) {
       
   225             restoreTransform = painter->worldTransform();
       
   226             painter->setWorldTransform(QTransform());
       
   227         }
       
   228 
       
   229         painter->drawPixmap(d->m_cachedOffset, pm);
       
   230 
       
   231         if (d->m_cachedSystem == Qt::DeviceCoordinates)
       
   232             painter->setWorldTransform(restoreTransform);
       
   233     } else {
       
   234         d_func()->draw(painter);
       
   235     }
       
   236 }
       
   237 
       
   238 /*!
       
   239     Draws the source directly using the given \a painter.
       
   240 
       
   241     This function should only be called from QGraphicsEffect::draw().
       
   242 
   206     For example:
   243     For example:
   207 
   244 
   208     \snippet doc/src/snippets/code/src_gui_effects_qgraphicseffect.cpp 0
   245     \snippet doc/src/snippets/code/src_gui_effects_qgraphicseffect.cpp 0
   209 
   246 
   210     \sa QGraphicsEffect::draw()
   247     \sa QGraphicsEffect::draw()
   211 */
   248 */
   212 void QGraphicsEffectSource::draw(QPainter *painter)
   249 void QGraphicsEffect::drawSource(QPainter *painter)
   213 {
   250 {
   214     d_func()->draw(painter);
   251     Q_D(const QGraphicsEffect);
       
   252     if (d->source)
       
   253         d->source->draw(painter);
   215 }
   254 }
   216 
   255 
   217 /*!
   256 /*!
   218     Schedules a redraw of the source. Call this function whenever the source
   257     Schedules a redraw of the source. Call this function whenever the source
   219     needs to be redrawn.
   258     needs to be redrawn.
   238 {
   277 {
   239     return d_func()->isPixmap();
   278     return d_func()->isPixmap();
   240 }
   279 }
   241 
   280 
   242 /*!
   281 /*!
       
   282     Returns true if the source effectively is a pixmap, e.g., a
       
   283     QGraphicsPixmapItem.
       
   284 
       
   285     This function is useful for optimization purposes. For instance, there's no
       
   286     point in drawing the source in device coordinates to avoid pixmap scaling
       
   287     if this function returns true - the source pixmap will be scaled anyways.
       
   288 */
       
   289 bool QGraphicsEffect::sourceIsPixmap() const
       
   290 {
       
   291     return source() ? source()->isPixmap() : false;
       
   292 }
       
   293 
       
   294 /*!
   243     Returns a pixmap with the source painted into it.
   295     Returns a pixmap with the source painted into it.
   244 
   296 
   245     The \a system specifies which coordinate system to be used for the source.
   297     The \a system specifies which coordinate system to be used for the source.
   246     The optional \a offset parameter returns the offset where the pixmap should
   298     The optional \a offset parameter returns the offset where the pixmap should
   247     be painted at using the current painter.
   299     be painted at using the current painter.
   248 
   300 
       
   301     The \a mode determines how much of the effect the pixmap will contain.
       
   302     By default, the pixmap will contain the whole effect.
       
   303 
   249     The returned pixmap is bound to the current painter's device rectangle when
   304     The returned pixmap is bound to the current painter's device rectangle when
   250     \a system is Qt::DeviceCoordinates.
   305     \a system is Qt::DeviceCoordinates.
   251 
   306 
   252     \sa QGraphicsEffect::draw(), boundingRect(), deviceRect()
   307     \sa QGraphicsEffect::draw(), boundingRect()
   253 */
   308 */
   254 QPixmap QGraphicsEffectSource::pixmap(Qt::CoordinateSystem system, QPoint *offset) const
   309 QPixmap QGraphicsEffectSource::pixmap(Qt::CoordinateSystem system, QPoint *offset, QGraphicsEffect::PixmapPadMode mode) const
   255 {
   310 {
   256     Q_D(const QGraphicsEffectSource);
   311     Q_D(const QGraphicsEffectSource);
   257 
   312 
       
   313     // Shortcut, no cache for childless pixmap items...
       
   314     const QGraphicsItem *item = graphicsItem();
       
   315     if (system == Qt::LogicalCoordinates && mode == QGraphicsEffect::NoPad && item && isPixmap()) {
       
   316         const QGraphicsPixmapItem *pixmapItem = static_cast<const QGraphicsPixmapItem *>(item);
       
   317         if (offset)
       
   318             *offset = pixmapItem->offset().toPoint();
       
   319         return pixmapItem->pixmap();
       
   320     }
       
   321 
       
   322     if (system == Qt::DeviceCoordinates && item
       
   323         && !static_cast<const QGraphicsItemEffectSourcePrivate *>(d_func())->info) {
       
   324         qWarning("QGraphicsEffectSource::pixmap: Not yet implemented, lacking device context");
       
   325         return QPixmap();
       
   326     }
       
   327 
   258     QPixmap pm;
   328     QPixmap pm;
   259     if (d->m_cachedSystem == system)
   329     if (d->m_cachedSystem == system && d->m_cachedMode == mode)
   260         QPixmapCache::find(d->m_cacheKey, &pm);
   330         QPixmapCache::find(d->m_cacheKey, &pm);
   261 
   331 
   262     if (pm.isNull()) {
   332     if (pm.isNull()) {
   263         pm = d->pixmap(system, &d->m_cachedOffset);
   333         pm = d->pixmap(system, &d->m_cachedOffset, mode);
   264         d->m_cachedSystem = system;
   334         d->m_cachedSystem = system;
       
   335         d->m_cachedMode = mode;
   265 
   336 
   266         d->invalidateCache();
   337         d->invalidateCache();
   267         d->m_cacheKey = QPixmapCache::insert(pm);
   338         d->m_cacheKey = QPixmapCache::insert(pm);
   268     }
   339     }
   269 
   340 
   272 
   343 
   273     return pm;
   344     return pm;
   274 }
   345 }
   275 
   346 
   276 /*!
   347 /*!
       
   348     Returns a pixmap with the source painted into it.
       
   349 
       
   350     The \a system specifies which coordinate system to be used for the source.
       
   351     The optional \a offset parameter returns the offset where the pixmap should
       
   352     be painted at using the current painter. For control on how the pixmap is
       
   353     padded use the \a mode parameter.
       
   354 
       
   355     The returned pixmap is clipped to the current painter's device rectangle when
       
   356     \a system is Qt::DeviceCoordinates.
       
   357 
       
   358     Calling this function with Qt::DeviceCoordinates outside of
       
   359     QGraphicsEffect::draw() will give undefined results, as there is no device
       
   360     context available.
       
   361 
       
   362     \sa draw(), boundingRect()
       
   363 */
       
   364 QPixmap QGraphicsEffect::sourcePixmap(Qt::CoordinateSystem system, QPoint *offset, QGraphicsEffect::PixmapPadMode mode) const
       
   365 {
       
   366     Q_D(const QGraphicsEffect);
       
   367     if (d->source)
       
   368         return d->source->pixmap(system, offset, mode);
       
   369     return QPixmap();
       
   370 }
       
   371 
       
   372 QGraphicsEffectSourcePrivate::~QGraphicsEffectSourcePrivate()
       
   373 {
       
   374     invalidateCache();
       
   375 }
       
   376 
       
   377 void QGraphicsEffectSourcePrivate::invalidateCache(InvalidateReason reason) const
       
   378 {
       
   379     if (m_cachedMode != QGraphicsEffect::PadToEffectiveBoundingRect
       
   380         && (reason == EffectRectChanged
       
   381             || reason == TransformChanged
       
   382                && m_cachedSystem == Qt::LogicalCoordinates))
       
   383         return;
       
   384 
       
   385     QPixmapCache::remove(m_cacheKey);
       
   386 }
       
   387 
       
   388 /*!
   277     Constructs a new QGraphicsEffect instance having the
   389     Constructs a new QGraphicsEffect instance having the
   278     specified \a parent.
   390     specified \a parent.
   279 */
   391 */
   280 QGraphicsEffect::QGraphicsEffect(QObject *parent)
   392 QGraphicsEffect::QGraphicsEffect(QObject *parent)
   281     : QObject(*new QGraphicsEffectPrivate, parent)
   393     : QObject(*new QGraphicsEffectPrivate, parent)
   298     Q_D(QGraphicsEffect);
   410     Q_D(QGraphicsEffect);
   299     d->setGraphicsEffectSource(0);
   411     d->setGraphicsEffectSource(0);
   300 }
   412 }
   301 
   413 
   302 /*!
   414 /*!
   303     Returns the bounding rectangle for this effect, i.e., the bounding
   415     Returns the effective bounding rectangle for this effect, i.e., the
   304     rectangle of the source, adjusted by any margins applied by the effect
   416     bounding rectangle of the source in device coordinates, adjusted by
   305     itself.
   417     any margins applied by the effect itself.
   306 
   418 
   307     \sa boundingRectFor(), updateBoundingRect()
   419     \sa boundingRectFor(), updateBoundingRect()
   308 */
   420 */
   309 QRectF QGraphicsEffect::boundingRect() const
   421 QRectF QGraphicsEffect::boundingRect() const
   310 {
   422 {
   313         return boundingRectFor(d->source->boundingRect());
   425         return boundingRectFor(d->source->boundingRect());
   314     return QRectF();
   426     return QRectF();
   315 }
   427 }
   316 
   428 
   317 /*!
   429 /*!
   318     Returns the bounding rectangle for this effect, given the provided source
   430     Returns the effective bounding rectangle for this effect, given the
   319     \a rect. When writing you own custom effect, you must call
   431     provided \a rect in the device coordinates. When writing
   320     updateBoundingRect() whenever any parameters are changed that may cause
   432     you own custom effect, you must call updateBoundingRect() whenever any
   321     this this function to return a different value.
   433     parameters are changed that may cause this this function to return a
   322 
   434     different value.
   323     \sa boundingRect()
   435 
       
   436     \sa sourceBoundingRect()
   324 */
   437 */
   325 QRectF QGraphicsEffect::boundingRectFor(const QRectF &rect) const
   438 QRectF QGraphicsEffect::boundingRectFor(const QRectF &rect) const
   326 {
   439 {
   327     return rect;
   440     return rect;
   328 }
   441 }
   351     Q_D(QGraphicsEffect);
   464     Q_D(QGraphicsEffect);
   352     if (d->isEnabled == enable)
   465     if (d->isEnabled == enable)
   353         return;
   466         return;
   354 
   467 
   355     d->isEnabled = enable;
   468     d->isEnabled = enable;
   356     if (d->source)
   469     if (d->source) {
   357         d->source->d_func()->effectBoundingRectChanged();
   470         d->source->d_func()->effectBoundingRectChanged();
       
   471         d->source->d_func()->invalidateCache();
       
   472     }
   358     emit enabledChanged(enable);
   473     emit enabledChanged(enable);
   359 }
   474 }
   360 
   475 
   361 /*!
   476 /*!
   362     \fn void QGraphicsEffect::enabledChanged(bool enabled)
   477     \fn void QGraphicsEffect::enabledChanged(bool enabled)
   382     if (d->source)
   497     if (d->source)
   383         d->source->update();
   498         d->source->update();
   384 }
   499 }
   385 
   500 
   386 /*!
   501 /*!
       
   502     \internal
       
   503 
   387     Returns a pointer to the source, which provides extra context information
   504     Returns a pointer to the source, which provides extra context information
   388     that can be useful for the effect.
   505     that can be useful for the effect.
   389 
   506 
   390     \sa draw()
   507     \sa draw()
   391 */
   508 */
   401     function whenever you change any parameters that will cause the virtual
   518     function whenever you change any parameters that will cause the virtual
   402     boundingRectFor() function to return a different value.
   519     boundingRectFor() function to return a different value.
   403 
   520 
   404     This function will call update() if this is necessary.
   521     This function will call update() if this is necessary.
   405 
   522 
   406     \sa boundingRectFor(), boundingRect()
   523     \sa boundingRectFor(), boundingRect(), sourceBoundingRect()
   407 */
   524 */
   408 void QGraphicsEffect::updateBoundingRect()
   525 void QGraphicsEffect::updateBoundingRect()
   409 {
   526 {
   410     Q_D(QGraphicsEffect);
   527     Q_D(QGraphicsEffect);
   411     if (d->source)
   528     if (d->source) {
   412         d->source->d_func()->effectBoundingRectChanged();
   529         d->source->d_func()->effectBoundingRectChanged();
   413 }
   530         d->source->d_func()->invalidateCache(QGraphicsEffectSourcePrivate::EffectRectChanged);
   414 
   531     }
   415 /*!
   532 }
   416     \fn virtual void QGraphicsEffect::draw(QPainter *painter,
   533 
   417     QGraphicsEffectSource *source) = 0
   534 /*!
       
   535     \fn virtual void QGraphicsEffect::draw(QPainter *painter) = 0
   418 
   536 
   419     This pure virtual function draws the effect and is called whenever the
   537     This pure virtual function draws the effect and is called whenever the
   420     source() needs to be drawn.
   538     source needs to be drawn.
   421 
   539 
   422     Reimplement this function in a QGraphicsEffect subclass to provide the
   540     Reimplement this function in a QGraphicsEffect subclass to provide the
   423     effect's drawing implementation, using \a painter. The \a source parameter
   541     effect's drawing implementation, using \a painter.
   424     is provided for convenience; its value is the same as source().
       
   425 
   542 
   426     For example:
   543     For example:
   427 
   544 
   428     \snippet doc/src/snippets/code/src_gui_effects_qgraphicseffect.cpp 1
   545     \snippet doc/src/snippets/code/src_gui_effects_qgraphicseffect.cpp 1
   429 
   546 
   430     This function should not be called explicitly by the user, since it is
   547     This function should not be called explicitly by the user, since it is
   431     meant for reimplementation purposes only.
   548     meant for reimplementation purposes only.
   432 
       
   433     \sa QGraphicsEffectSource
       
   434 */
   549 */
   435 
   550 
   436 /*!
   551 /*!
   437     \enum QGraphicsEffect::ChangeFlag
   552     \enum QGraphicsEffect::ChangeFlag
   438 
   553 
   444            changed.
   559            changed.
   445     \value SourceInvalidated The visual appearance of the source has changed.
   560     \value SourceInvalidated The visual appearance of the source has changed.
   446 */
   561 */
   447 
   562 
   448 /*!
   563 /*!
       
   564     \enum QGraphicsEffect::PixmapPadMode
       
   565 
       
   566     This enum describes how the pixmap returned from sourcePixmap should be
       
   567     padded.
       
   568 
       
   569     \value NoPad The pixmap should not receive any additional
       
   570            padding.
       
   571     \value PadToTransparentBorder The pixmap should be padded
       
   572            to ensure it has a completely transparent border.
       
   573     \value PadToEffectiveBoundingRect The pixmap should be padded to
       
   574            match the effective bounding rectangle of the effect.
       
   575 */
       
   576 
       
   577 /*!
   449     This virtual function is called by QGraphicsEffect to notify the effect
   578     This virtual function is called by QGraphicsEffect to notify the effect
   450     that the source has changed. If the effect applies any cache, then this
   579     that the source has changed. If the effect applies any cache, then this
   451     cache must be purged in order to reflect the new appearance of the source.
   580     cache must be purged in order to reflect the new appearance of the source.
   452 
   581 
   453     The \a flags describes what has changed.
   582     The \a flags describes what has changed.
   456 {
   585 {
   457     Q_UNUSED(flags);
   586     Q_UNUSED(flags);
   458 }
   587 }
   459 
   588 
   460 /*!
   589 /*!
   461     \class QGraphicsGrayscaleEffect
       
   462     \brief The QGraphicsGrayscaleEffect class provides a grayscale effect.
       
   463     \since 4.6
       
   464 
       
   465     A grayscale effect renders the source in shades of gray.
       
   466 
       
   467     \img graphicseffect-grayscale.png
       
   468 
       
   469     \sa QGraphicsDropShadowEffect, QGraphicsBlurEffect, QGraphicsPixelizeEffect,
       
   470         QGraphicsColorizeEffect, QGraphicsOpacityEffect
       
   471 */
       
   472 
       
   473 /*!
       
   474     Constructs a new QGraphicsGrayscale instance.
       
   475     The \a parent parameter is passed to QGraphicsEffect's constructor.
       
   476 */
       
   477 QGraphicsGrayscaleEffect::QGraphicsGrayscaleEffect(QObject *parent)
       
   478     : QGraphicsEffect(*new QGraphicsGrayscaleEffectPrivate, parent)
       
   479 {
       
   480 }
       
   481 
       
   482 /*!
       
   483     Destroys the effect.
       
   484 */
       
   485 QGraphicsGrayscaleEffect::~QGraphicsGrayscaleEffect()
       
   486 {
       
   487 }
       
   488 
       
   489 
       
   490 /*!
       
   491     \property QGraphicsGrayscaleEffect::strength
       
   492     \brief the strength of the effect.
       
   493 
       
   494     By default, the strength is 1.0.
       
   495     A strength 0.0 equals to no effect, while 1.0 means full grayscale.
       
   496 */
       
   497 qreal QGraphicsGrayscaleEffect::strength() const
       
   498 {
       
   499     Q_D(const QGraphicsGrayscaleEffect);
       
   500     return d->filter->strength();
       
   501 }
       
   502 
       
   503 void QGraphicsGrayscaleEffect::setStrength(qreal strength)
       
   504 {
       
   505     Q_D(QGraphicsGrayscaleEffect);
       
   506     if (qFuzzyCompare(d->filter->strength(), strength))
       
   507         return;
       
   508 
       
   509     d->filter->setStrength(strength);
       
   510     d->opaque = !qFuzzyIsNull(strength);
       
   511     update();
       
   512     emit strengthChanged(strength);
       
   513 }
       
   514 
       
   515 /*! \fn void QGraphicsGrayscaleEffect::strengthChanged(qreal strength)
       
   516   This signal is emitted whenever setStrength() changes the grayscale
       
   517   strength property. \a strength contains the new strength value of
       
   518   the grayscale effect.
       
   519  */
       
   520 
       
   521 /*!
       
   522     \reimp
       
   523 */
       
   524 void QGraphicsGrayscaleEffect::draw(QPainter *painter, QGraphicsEffectSource *source)
       
   525 {
       
   526     Q_D(QGraphicsGrayscaleEffect);
       
   527 
       
   528     if (!d->opaque) {
       
   529         source->draw(painter);
       
   530         return;
       
   531     }
       
   532 
       
   533     QPoint offset;
       
   534     if (source->isPixmap()) {
       
   535         // No point in drawing in device coordinates (pixmap will be scaled anyways).
       
   536         const QPixmap pixmap = source->pixmap(Qt::LogicalCoordinates, &offset);
       
   537         d->filter->draw(painter, offset, pixmap);
       
   538         return;
       
   539     }
       
   540 
       
   541     // Draw pixmap in device coordinates to avoid pixmap scaling;
       
   542     const QPixmap pixmap = source->pixmap(Qt::DeviceCoordinates, &offset);
       
   543     QTransform restoreTransform = painter->worldTransform();
       
   544     painter->setWorldTransform(QTransform());
       
   545     d->filter->draw(painter, offset, pixmap);
       
   546     painter->setWorldTransform(restoreTransform);
       
   547 
       
   548 }
       
   549 
       
   550 /*!
       
   551     \class QGraphicsColorizeEffect
   590     \class QGraphicsColorizeEffect
   552     \brief The QGraphicsColorizeEffect class provides a colorize effect.
   591     \brief The QGraphicsColorizeEffect class provides a colorize effect.
   553     \since 4.6
   592     \since 4.6
   554 
   593 
   555     A colorize effect renders the source with a tint of its color(). The color
   594     A colorize effect renders the source with a tint of its color(). The color
   557 
   596 
   558     By default, the color is light blue (QColor(0, 0, 192)).
   597     By default, the color is light blue (QColor(0, 0, 192)).
   559 
   598 
   560     \img graphicseffect-colorize.png
   599     \img graphicseffect-colorize.png
   561 
   600 
   562     \sa QGraphicsDropShadowEffect, QGraphicsBlurEffect, QGraphicsPixelizeEffect,
   601     \sa QGraphicsDropShadowEffect, QGraphicsBlurEffect, QGraphicsOpacityEffect
   563         QGraphicsGrayscaleEffect, QGraphicsOpacityEffect
       
   564 */
   602 */
   565 
   603 
   566 /*!
   604 /*!
   567     Constructs a new QGraphicsColorizeEffect instance.
   605     Constructs a new QGraphicsColorizeEffect instance.
   568     The \a parent parameter is passed to QGraphicsEffect's constructor.
   606     The \a parent parameter is passed to QGraphicsEffect's constructor.
   641 */
   679 */
   642 
   680 
   643 /*!
   681 /*!
   644     \reimp
   682     \reimp
   645 */
   683 */
   646 void QGraphicsColorizeEffect::draw(QPainter *painter, QGraphicsEffectSource *source)
   684 void QGraphicsColorizeEffect::draw(QPainter *painter)
   647 {
   685 {
   648     Q_D(QGraphicsColorizeEffect);
   686     Q_D(QGraphicsColorizeEffect);
   649 
   687 
   650     if (!d->opaque) {
   688     if (!d->opaque) {
   651         source->draw(painter);
   689         drawSource(painter);
   652         return;
   690         return;
   653     }
   691     }
   654 
   692 
   655     QPoint offset;
   693     QPoint offset;
   656     if (source->isPixmap()) {
   694     if (sourceIsPixmap()) {
   657         // No point in drawing in device coordinates (pixmap will be scaled anyways).
   695         // No point in drawing in device coordinates (pixmap will be scaled anyways).
   658         const QPixmap pixmap = source->pixmap(Qt::LogicalCoordinates, &offset);
   696         const QPixmap pixmap = sourcePixmap(Qt::LogicalCoordinates, &offset, NoPad);
   659         d->filter->draw(painter, offset, pixmap);
   697         d->filter->draw(painter, offset, pixmap);
   660         return;
   698         return;
   661     }
   699     }
   662 
   700 
   663     // Draw pixmap in deviceCoordinates to avoid pixmap scaling.
   701     // Draw pixmap in deviceCoordinates to avoid pixmap scaling.
   664     const QPixmap pixmap = source->pixmap(Qt::DeviceCoordinates, &offset);
   702     const QPixmap pixmap = sourcePixmap(Qt::DeviceCoordinates, &offset);
   665     QTransform restoreTransform = painter->worldTransform();
   703     QTransform restoreTransform = painter->worldTransform();
   666     painter->setWorldTransform(QTransform());
   704     painter->setWorldTransform(QTransform());
   667     d->filter->draw(painter, offset, pixmap);
   705     d->filter->draw(painter, offset, pixmap);
   668     painter->setWorldTransform(restoreTransform);
   706     painter->setWorldTransform(restoreTransform);
   669 }
   707 }
   670 
   708 
   671 /*!
   709 /*!
   672     \class QGraphicsPixelizeEffect
       
   673     \brief The QGraphicsPixelizeEffect class provides a pixelize effect.
       
   674     \since 4.6
       
   675 
       
   676     A pixelize effect renders the source in lower resolution. This effect is
       
   677     useful for reducing details, like censorship. The resolution can be
       
   678     modified using the setPixelSize() function.
       
   679 
       
   680     By default, the pixel size is 3.
       
   681 
       
   682     \img graphicseffect-pixelize.png
       
   683 
       
   684     \sa QGraphicsDropShadowEffect, QGraphicsBlurEffect, QGraphicsGrayscaleEffect,
       
   685         QGraphicsColorizeEffect, QGraphicsOpacityEffect
       
   686 */
       
   687 
       
   688 /*!
       
   689     Constructs a new QGraphicsPixelizeEffect instance.
       
   690     The \a parent parameter is passed to QGraphicsEffect's constructor.
       
   691 */
       
   692 QGraphicsPixelizeEffect::QGraphicsPixelizeEffect(QObject *parent)
       
   693     : QGraphicsEffect(*new QGraphicsPixelizeEffectPrivate, parent)
       
   694 {
       
   695 }
       
   696 
       
   697 /*!
       
   698     Destroys the effect.
       
   699 */
       
   700 QGraphicsPixelizeEffect::~QGraphicsPixelizeEffect()
       
   701 {
       
   702 }
       
   703 
       
   704 /*!
       
   705     \property QGraphicsPixelizeEffect::pixelSize
       
   706     \brief the size of a pixel in the effect.
       
   707 
       
   708     Setting the pixel size to 2 means two pixels in the source will be used to
       
   709     represent one pixel. Using a bigger size results in lower resolution.
       
   710 
       
   711     By default, the pixel size is 3.
       
   712 */
       
   713 int QGraphicsPixelizeEffect::pixelSize() const
       
   714 {
       
   715     Q_D(const QGraphicsPixelizeEffect);
       
   716     return d->pixelSize;
       
   717 }
       
   718 
       
   719 void QGraphicsPixelizeEffect::setPixelSize(int size)
       
   720 {
       
   721     Q_D(QGraphicsPixelizeEffect);
       
   722     if (d->pixelSize == size)
       
   723         return;
       
   724 
       
   725     d->pixelSize = size;
       
   726     update();
       
   727     emit pixelSizeChanged(size);
       
   728 }
       
   729 
       
   730 /*!
       
   731     \fn void QGraphicsPixelizeEffect::pixelSizeChanged(int size)
       
   732 
       
   733     This signal is emitted whenever the effect's pixel size changes.
       
   734     The \a size parameter holds the effect's new pixel size.
       
   735 */
       
   736 
       
   737 static inline void pixelize(QImage *image, int pixelSize)
       
   738 {
       
   739     Q_ASSERT(pixelSize > 0);
       
   740     Q_ASSERT(image);
       
   741     int width = image->width();
       
   742     int height = image->height();
       
   743     for (int y = 0; y < height; y += pixelSize) {
       
   744         int ys = qMin(height - 1, y + pixelSize / 2);
       
   745         QRgb *sbuf = reinterpret_cast<QRgb*>(image->scanLine(ys));
       
   746         for (int x = 0; x < width; x += pixelSize) {
       
   747             int xs = qMin(width - 1, x + pixelSize / 2);
       
   748             QRgb color = sbuf[xs];
       
   749             for (int yi = 0; yi < qMin(pixelSize, height - y); ++yi) {
       
   750                 QRgb *buf = reinterpret_cast<QRgb*>(image->scanLine(y + yi));
       
   751                 for (int xi = 0; xi < qMin(pixelSize, width - x); ++xi)
       
   752                     buf[x + xi] = color;
       
   753             }
       
   754         }
       
   755     }
       
   756 }
       
   757 
       
   758 /*!
       
   759     \reimp
       
   760 */
       
   761 void QGraphicsPixelizeEffect::draw(QPainter *painter, QGraphicsEffectSource *source)
       
   762 {
       
   763     Q_D(QGraphicsPixelizeEffect);
       
   764     if (d->pixelSize <= 0) {
       
   765         source->draw(painter);
       
   766         return;
       
   767     }
       
   768 
       
   769     QPoint offset;
       
   770     if (source->isPixmap()) {
       
   771         const QPixmap pixmap = source->pixmap(Qt::LogicalCoordinates, &offset);
       
   772         QImage image = pixmap.toImage().convertToFormat(QImage::Format_ARGB32);
       
   773         pixelize(&image, d->pixelSize);
       
   774         painter->drawImage(offset, image);
       
   775         return;
       
   776     }
       
   777 
       
   778     // Draw pixmap in device coordinates to avoid pixmap scaling.
       
   779     const QPixmap pixmap = source->pixmap(Qt::DeviceCoordinates, &offset);
       
   780 
       
   781     // pixelize routine
       
   782     QImage image = pixmap.toImage().convertToFormat(QImage::Format_ARGB32);
       
   783     pixelize(&image, d->pixelSize);
       
   784 
       
   785     QTransform restoreTransform = painter->worldTransform();
       
   786     painter->setWorldTransform(QTransform());
       
   787     painter->drawImage(offset, image);
       
   788     painter->setWorldTransform(restoreTransform);
       
   789 }
       
   790 
       
   791 /*!
       
   792     \class QGraphicsBlurEffect
   710     \class QGraphicsBlurEffect
   793     \brief The QGraphicsBlurEffect class provides a blur effect.
   711     \brief The QGraphicsBlurEffect class provides a blur effect.
   794     \since 4.6
   712     \since 4.6
   795 
   713 
   796     A blur effect blurs the source. This effect is useful for reducing details,
   714     A blur effect blurs the source. This effect is useful for reducing details,
   797     such as when the source loses focus and you want to draw attention to other
   715     such as when the source loses focus and you want to draw attention to other
   798     elements. The level of detail can be modified using the setBlurRadius()
   716     elements. The level of detail can be modified using the setBlurRadius()
   799     function. Use setBlurHint() to choose the quality or performance blur hints.
   717     function. Use setBlurHints() to choose the blur hints.
   800 
   718 
   801     By default, the blur radius is 5 pixels.
   719     By default, the blur radius is 5 pixels.
   802 
   720 
   803     \img graphicseffect-blur.png
   721     \img graphicseffect-blur.png
   804 
   722 
   805     \sa QGraphicsDropShadowEffect, QGraphicsPixelizeEffect, QGraphicsGrayscaleEffect,
   723     \sa QGraphicsDropShadowEffect, QGraphicsColorizeEffect, QGraphicsOpacityEffect
   806         QGraphicsColorizeEffect, QGraphicsOpacityEffect
   724 */
   807 */
   725 
       
   726 /*!
       
   727     \enum QGraphicsBlurEffect::BlurHint
       
   728     \since 4.6
       
   729 
       
   730     This enum describes the possible hints that can be used to control how
       
   731     blur effects are applied. The hints might not have an effect in all the
       
   732     paint engines.
       
   733 
       
   734     \value PerformanceHint Indicates that rendering performance is the most important factor,
       
   735     at the potential cost of lower quality.
       
   736 
       
   737     \value QualityHint Indicates that rendering quality is the most important factor,
       
   738     at the potential cost of lower performance.
       
   739 
       
   740     \value AnimationHint Indicates that the blur radius is going to be animated, hinting
       
   741     that the implementation can keep a cache of blurred verisons of the source.
       
   742     Do not use this hint if the source is going to be dynamically changing.
       
   743 
       
   744     \sa blurHints(), setBlurHints()
       
   745 */
       
   746 
   808 
   747 
   809 /*!
   748 /*!
   810     Constructs a new QGraphicsBlurEffect instance.
   749     Constructs a new QGraphicsBlurEffect instance.
   811     The \a parent parameter is passed to QGraphicsEffect's constructor.
   750     The \a parent parameter is passed to QGraphicsEffect's constructor.
   812 */
   751 */
   813 QGraphicsBlurEffect::QGraphicsBlurEffect(QObject *parent)
   752 QGraphicsBlurEffect::QGraphicsBlurEffect(QObject *parent)
   814     : QGraphicsEffect(*new QGraphicsBlurEffectPrivate, parent)
   753     : QGraphicsEffect(*new QGraphicsBlurEffectPrivate, parent)
   815 {
   754 {
   816     Q_D(QGraphicsBlurEffect);
   755     Q_D(QGraphicsBlurEffect);
   817     d->filter->setBlurHint(Qt::PerformanceHint);
   756     d->filter->setBlurHints(QGraphicsBlurEffect::PerformanceHint);
   818 }
   757 }
   819 
   758 
   820 /*!
   759 /*!
   821     Destroys the effect.
   760     Destroys the effect.
   822 */
   761 */
   831     Using a smaller radius results in a sharper appearance, whereas a bigger
   770     Using a smaller radius results in a sharper appearance, whereas a bigger
   832     radius results in a more blurred appearance.
   771     radius results in a more blurred appearance.
   833 
   772 
   834     By default, the blur radius is 5 pixels.
   773     By default, the blur radius is 5 pixels.
   835 */
   774 */
   836 int QGraphicsBlurEffect::blurRadius() const
   775 qreal QGraphicsBlurEffect::blurRadius() const
   837 {
   776 {
   838     Q_D(const QGraphicsBlurEffect);
   777     Q_D(const QGraphicsBlurEffect);
   839     return d->filter->radius();
   778     return d->filter->radius();
   840 }
   779 }
   841 
   780 
   842 void QGraphicsBlurEffect::setBlurRadius(int radius)
   781 void QGraphicsBlurEffect::setBlurRadius(qreal radius)
   843 {
   782 {
   844     Q_D(QGraphicsBlurEffect);
   783     Q_D(QGraphicsBlurEffect);
   845     if (d->filter->radius() == radius)
   784     if (qFuzzyCompare(d->filter->radius(), radius))
   846         return;
   785         return;
   847 
   786 
   848     d->filter->setRadius(radius);
   787     d->filter->setRadius(radius);
   849     updateBoundingRect();
   788     updateBoundingRect();
   850     emit blurRadiusChanged(radius);
   789     emit blurRadiusChanged(radius);
   851 }
   790 }
   852 
   791 
   853 /*!
   792 /*!
   854     \fn void QGraphicsBlurEffect::blurRadiusChanged(int radius)
   793     \fn void QGraphicsBlurEffect::blurRadiusChanged(qreal radius)
   855 
   794 
   856     This signal is emitted whenever the effect's blur radius changes.
   795     This signal is emitted whenever the effect's blur radius changes.
   857     The \a radius parameter holds the effect's new blur radius.
   796     The \a radius parameter holds the effect's new blur radius.
   858 */
   797 */
   859 
   798 
   860 /*!
   799 /*!
   861     \property QGraphicsBlurEffect::blurHint
   800     \property QGraphicsBlurEffect::blurHints
   862     \brief the blur hint of the effect.
   801     \brief the blur hint of the effect.
   863 
   802 
   864     Use the Qt::PerformanceHint hint to say that you want a faster blur,
   803     Use the PerformanceHint hint to say that you want a faster blur,
   865     and the Qt::QualityHint hint to say that you prefer a higher quality blur.
   804     the QualityHint hint to say that you prefer a higher quality blur,
   866 
   805     or the AnimationHint when you want to animate the blur radius.
   867     When animating the blur radius it's recommended to use Qt::PerformanceHint.
   806 
   868 
   807     By default, the blur hint is PerformanceHint.
   869     By default, the blur hint is Qt::PerformanceHint.
   808 */
   870 */
   809 QGraphicsBlurEffect::BlurHints QGraphicsBlurEffect::blurHints() const
   871 Qt::RenderHint QGraphicsBlurEffect::blurHint() const
       
   872 {
   810 {
   873     Q_D(const QGraphicsBlurEffect);
   811     Q_D(const QGraphicsBlurEffect);
   874     return d->filter->blurHint();
   812     return d->filter->blurHints();
   875 }
   813 }
   876 
   814 
   877 void QGraphicsBlurEffect::setBlurHint(Qt::RenderHint hint)
   815 void QGraphicsBlurEffect::setBlurHints(QGraphicsBlurEffect::BlurHints hints)
   878 {
   816 {
   879     Q_D(QGraphicsBlurEffect);
   817     Q_D(QGraphicsBlurEffect);
   880     if (d->filter->blurHint() == hint)
   818     if (d->filter->blurHints() == hints)
   881         return;
   819         return;
   882 
   820 
   883     d->filter->setBlurHint(hint);
   821     d->filter->setBlurHints(hints);
   884     emit blurHintChanged(hint);
   822     emit blurHintsChanged(hints);
   885 }
   823 }
   886 
   824 
   887 /*!
   825 /*!
   888     \fn void QGraphicsBlurEffect::blurHintChanged(Qt::RenderHint hint)
   826     \fn void QGraphicsBlurEffect::blurHintsChanged(QGraphicsBlurEffect::BlurHints hints)
   889 
   827 
   890     This signal is emitted whenever the effect's blur hint changes.
   828     This signal is emitted whenever the effect's blur hints changes.
   891     The \a hint parameter holds the effect's new blur hint.
   829     The \a hints parameter holds the effect's new blur hints.
   892 */
   830 */
   893 
   831 
   894 /*!
   832 /*!
   895     \reimp
   833     \reimp
   896 */
   834 */
   901 }
   839 }
   902 
   840 
   903 /*!
   841 /*!
   904     \reimp
   842     \reimp
   905 */
   843 */
   906 void QGraphicsBlurEffect::draw(QPainter *painter, QGraphicsEffectSource *source)
   844 void QGraphicsBlurEffect::draw(QPainter *painter)
   907 {
   845 {
   908     Q_D(QGraphicsBlurEffect);
   846     Q_D(QGraphicsBlurEffect);
   909     if (d->filter->radius() <= 0) {
   847     if (d->filter->radius() < 1) {
   910         source->draw(painter);
   848         drawSource(painter);
   911         return;
   849         return;
   912     }
   850     }
       
   851 
       
   852     PixmapPadMode mode = PadToEffectiveBoundingRect;
       
   853     if (painter->paintEngine()->type() == QPaintEngine::OpenGL2)
       
   854         mode = NoPad;
   913 
   855 
   914     // Draw pixmap in device coordinates to avoid pixmap scaling.
   856     // Draw pixmap in device coordinates to avoid pixmap scaling.
   915     QPoint offset;
   857     QPoint offset;
   916     const QPixmap pixmap = source->pixmap(Qt::DeviceCoordinates, &offset);
   858     QPixmap pixmap = sourcePixmap(Qt::LogicalCoordinates, &offset, mode);
   917     QTransform restoreTransform = painter->worldTransform();
       
   918     painter->setWorldTransform(QTransform());
       
   919     d->filter->draw(painter, offset, pixmap);
   859     d->filter->draw(painter, offset, pixmap);
   920     painter->setWorldTransform(restoreTransform);
       
   921 }
   860 }
   922 
   861 
   923 /*!
   862 /*!
   924     \class QGraphicsDropShadowEffect
   863     \class QGraphicsDropShadowEffect
   925     \brief The QGraphicsDropShadowEffect class provides a drop shadow effect.
   864     \brief The QGraphicsDropShadowEffect class provides a drop shadow effect.
   935     (QColor(63, 63, 63, 180)) shadow, blurred with a radius of 1 at an offset
   874     (QColor(63, 63, 63, 180)) shadow, blurred with a radius of 1 at an offset
   936     of 8 pixels towards the lower right.
   875     of 8 pixels towards the lower right.
   937 
   876 
   938     \img graphicseffect-drop-shadow.png
   877     \img graphicseffect-drop-shadow.png
   939 
   878 
   940     \sa QGraphicsBlurEffect, QGraphicsPixelizeEffect, QGraphicsGrayscaleEffect,
   879     \sa QGraphicsBlurEffect, QGraphicsColorizeEffect, QGraphicsOpacityEffect
   941         QGraphicsColorizeEffect, QGraphicsOpacityEffect
       
   942 */
   880 */
   943 
   881 
   944 /*!
   882 /*!
   945     Constructs a new QGraphicsDropShadowEffect instance.
   883     Constructs a new QGraphicsDropShadowEffect instance.
   946     The \a parent parameter is passed to QGraphicsEffect's constructor.
   884     The \a parent parameter is passed to QGraphicsEffect's constructor.
   986     \property QGraphicsDropShadowEffect::xOffset
   924     \property QGraphicsDropShadowEffect::xOffset
   987     \brief the horizontal shadow offset in pixels.
   925     \brief the horizontal shadow offset in pixels.
   988 
   926 
   989     By default, the horizontal shadow offset is 8 pixels.
   927     By default, the horizontal shadow offset is 8 pixels.
   990 
   928 
       
   929 
       
   930 
   991     \sa yOffset(), offset()
   931     \sa yOffset(), offset()
   992 */
   932 */
   993 
   933 
   994 /*!
   934 /*!
   995     \property QGraphicsDropShadowEffect::yOffset
   935     \property QGraphicsDropShadowEffect::yOffset
  1016 
   956 
  1017     By default, the blur radius is 1 pixel.
   957     By default, the blur radius is 1 pixel.
  1018 
   958 
  1019     \sa color(), offset().
   959     \sa color(), offset().
  1020 */
   960 */
  1021 int QGraphicsDropShadowEffect::blurRadius() const
   961 qreal QGraphicsDropShadowEffect::blurRadius() const
  1022 {
   962 {
  1023     Q_D(const QGraphicsDropShadowEffect);
   963     Q_D(const QGraphicsDropShadowEffect);
  1024     return d->filter->blurRadius();
   964     return d->filter->blurRadius();
  1025 }
   965 }
  1026 
   966 
  1027 void QGraphicsDropShadowEffect::setBlurRadius(int blurRadius)
   967 void QGraphicsDropShadowEffect::setBlurRadius(qreal blurRadius)
  1028 {
   968 {
  1029     Q_D(QGraphicsDropShadowEffect);
   969     Q_D(QGraphicsDropShadowEffect);
  1030     if (d->filter->blurRadius() == blurRadius)
   970     if (qFuzzyCompare(d->filter->blurRadius(), blurRadius))
  1031         return;
   971         return;
  1032 
   972 
  1033     d->filter->setBlurRadius(blurRadius);
   973     d->filter->setBlurRadius(blurRadius);
  1034     updateBoundingRect();
   974     updateBoundingRect();
  1035     emit blurRadiusChanged(blurRadius);
   975     emit blurRadiusChanged(blurRadius);
  1036 }
   976 }
  1037 
   977 
  1038 /*!
   978 /*!
  1039     \fn void QGraphicsDropShadowEffect::blurRadiusChanged(int blurRadius)
   979     \fn void QGraphicsDropShadowEffect::blurRadiusChanged(qreal blurRadius)
  1040 
   980 
  1041     This signal is emitted whenever the effect's blur radius changes.
   981     This signal is emitted whenever the effect's blur radius changes.
  1042     The \a blurRadius parameter holds the effect's new blur radius.
   982     The \a blurRadius parameter holds the effect's new blur radius.
  1043 */
   983 */
  1044 
   984 
  1085 }
  1025 }
  1086 
  1026 
  1087 /*!
  1027 /*!
  1088     \reimp
  1028     \reimp
  1089 */
  1029 */
  1090 void QGraphicsDropShadowEffect::draw(QPainter *painter, QGraphicsEffectSource *source)
  1030 void QGraphicsDropShadowEffect::draw(QPainter *painter)
  1091 {
  1031 {
  1092     Q_D(QGraphicsDropShadowEffect);
  1032     Q_D(QGraphicsDropShadowEffect);
  1093     if (d->filter->blurRadius() <= 0 && d->filter->offset().isNull()) {
  1033     if (d->filter->blurRadius() <= 0 && d->filter->offset().isNull()) {
  1094         source->draw(painter);
  1034         drawSource(painter);
  1095         return;
  1035         return;
  1096     }
  1036     }
       
  1037 
       
  1038     PixmapPadMode mode = PadToEffectiveBoundingRect;
       
  1039     if (painter->paintEngine()->type() == QPaintEngine::OpenGL2)
       
  1040         mode = NoPad;
  1097 
  1041 
  1098     // Draw pixmap in device coordinates to avoid pixmap scaling.
  1042     // Draw pixmap in device coordinates to avoid pixmap scaling.
  1099     QPoint offset;
  1043     QPoint offset;
  1100     const QPixmap pixmap = source->pixmap(Qt::DeviceCoordinates, &offset);
  1044     const QPixmap pixmap = sourcePixmap(Qt::DeviceCoordinates, &offset, mode);
  1101     QTransform restoreTransform = painter->worldTransform();
  1045     QTransform restoreTransform = painter->worldTransform();
  1102     painter->setWorldTransform(QTransform());
  1046     painter->setWorldTransform(QTransform());
  1103     d->filter->draw(painter, offset, pixmap);
  1047     d->filter->draw(painter, offset, pixmap);
  1104     painter->setWorldTransform(restoreTransform);
  1048     painter->setWorldTransform(restoreTransform);
  1105 }
  1049 }
  1115 
  1059 
  1116     By default, the opacity is 0.7.
  1060     By default, the opacity is 0.7.
  1117 
  1061 
  1118     \img graphicseffect-opacity.png
  1062     \img graphicseffect-opacity.png
  1119 
  1063 
  1120     \sa QGraphicsDropShadowEffect, QGraphicsBlurEffect, QGraphicsPixelizeEffect,
  1064     \sa QGraphicsDropShadowEffect, QGraphicsBlurEffect, QGraphicsColorizeEffect
  1121         QGraphicsGrayscaleEffect, QGraphicsColorizeEffect
       
  1122 */
  1065 */
  1123 
  1066 
  1124 /*!
  1067 /*!
  1125     Constructs a new QGraphicsOpacityEffect instance.
  1068     Constructs a new QGraphicsOpacityEffect instance.
  1126     The \a parent parameter is passed to QGraphicsEffect's constructor.
  1069     The \a parent parameter is passed to QGraphicsEffect's constructor.
  1219 */
  1162 */
  1220 
  1163 
  1221 /*!
  1164 /*!
  1222     \reimp
  1165     \reimp
  1223 */
  1166 */
  1224 void QGraphicsOpacityEffect::draw(QPainter *painter, QGraphicsEffectSource *source)
  1167 void QGraphicsOpacityEffect::draw(QPainter *painter)
  1225 {
  1168 {
  1226     Q_D(QGraphicsOpacityEffect);
  1169     Q_D(QGraphicsOpacityEffect);
  1227 
  1170 
  1228     // Transparent; nothing to draw.
  1171     // Transparent; nothing to draw.
  1229     if (d->isFullyTransparent)
  1172     if (d->isFullyTransparent)
  1230         return;
  1173         return;
  1231 
  1174 
  1232     // Opaque; draw directly without going through a pixmap.
  1175     // Opaque; draw directly without going through a pixmap.
  1233     if (d->isFullyOpaque && !d->hasOpacityMask) {
  1176     if (d->isFullyOpaque && !d->hasOpacityMask) {
  1234         source->draw(painter);
  1177         drawSource(painter);
  1235         return;
  1178         return;
  1236     }
  1179     }
       
  1180 
       
  1181     QPoint offset;
       
  1182     Qt::CoordinateSystem system = sourceIsPixmap() ? Qt::LogicalCoordinates : Qt::DeviceCoordinates;
       
  1183     QPixmap pixmap = sourcePixmap(system, &offset, QGraphicsEffect::NoPad);
       
  1184     if (pixmap.isNull())
       
  1185         return;
  1237 
  1186 
  1238     painter->save();
  1187     painter->save();
  1239     painter->setOpacity(d->opacity);
  1188     painter->setOpacity(d->opacity);
  1240 
  1189 
  1241     QPoint offset;
  1190     if (d->hasOpacityMask) {
  1242     if (source->isPixmap()) {
  1191         QPainter pixmapPainter(&pixmap);
  1243         // No point in drawing in device coordinates (pixmap will be scaled anyways).
  1192         pixmapPainter.setRenderHints(painter->renderHints());
  1244         if (!d->hasOpacityMask) {
  1193         pixmapPainter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
  1245             const QPixmap pixmap = source->pixmap(Qt::LogicalCoordinates, &offset);
  1194         if (system == Qt::DeviceCoordinates) {
  1246             painter->drawPixmap(offset, pixmap);
  1195             QTransform worldTransform = painter->worldTransform();
       
  1196             worldTransform *= QTransform::fromTranslate(-offset.x(), -offset.y());
       
  1197             pixmapPainter.setWorldTransform(worldTransform);
       
  1198             pixmapPainter.fillRect(sourceBoundingRect(), d->opacityMask);
  1247         } else {
  1199         } else {
  1248             QRect srcBrect = source->boundingRect().toAlignedRect();
       
  1249             offset = srcBrect.topLeft();
       
  1250             QPixmap pixmap(srcBrect.size());
       
  1251             pixmap.fill(Qt::transparent);
       
  1252 
       
  1253             QPainter pixmapPainter(&pixmap);
       
  1254             pixmapPainter.setRenderHints(painter->renderHints());
       
  1255             pixmapPainter.translate(-offset);
  1200             pixmapPainter.translate(-offset);
  1256             source->draw(&pixmapPainter);
  1201             pixmapPainter.fillRect(pixmap.rect(), d->opacityMask);
  1257             pixmapPainter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
       
  1258             pixmapPainter.fillRect(srcBrect, d->opacityMask);
       
  1259             pixmapPainter.end();
       
  1260 
       
  1261             painter->drawPixmap(offset, pixmap);
       
  1262         }
       
  1263     } else {
       
  1264         // Draw pixmap in device coordinates to avoid pixmap scaling;
       
  1265         if (!d->hasOpacityMask) {
       
  1266             const QPixmap pixmap = source->pixmap(Qt::DeviceCoordinates, &offset);
       
  1267             painter->setWorldTransform(QTransform());
       
  1268             painter->drawPixmap(offset, pixmap);
       
  1269         } else {
       
  1270             QTransform worldTransform = painter->worldTransform();
       
  1271 
       
  1272             // Calculate source bounding rect in logical and device coordinates.
       
  1273             QRectF srcBrect = source->boundingRect();
       
  1274             QRect srcDeviceBrect = worldTransform.mapRect(srcBrect).toAlignedRect();
       
  1275             srcDeviceBrect &= source->deviceRect();
       
  1276 
       
  1277             offset = srcDeviceBrect.topLeft();
       
  1278             worldTransform *= QTransform::fromTranslate(-srcDeviceBrect.x(), -srcDeviceBrect.y());
       
  1279 
       
  1280             QPixmap pixmap(srcDeviceBrect.size());
       
  1281             pixmap.fill(Qt::transparent);
       
  1282 
       
  1283             QPainter pixmapPainter(&pixmap);
       
  1284             pixmapPainter.setRenderHints(painter->renderHints());
       
  1285             pixmapPainter.setWorldTransform(worldTransform);
       
  1286             source->draw(&pixmapPainter);
       
  1287             pixmapPainter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
       
  1288             pixmapPainter.fillRect(srcBrect, d->opacityMask);
       
  1289             pixmapPainter.end();
       
  1290 
       
  1291             painter->setWorldTransform(QTransform());
       
  1292             painter->drawPixmap(offset, pixmap);
       
  1293         }
  1202         }
  1294     }
  1203     }
  1295 
  1204 
       
  1205     if (system == Qt::DeviceCoordinates)
       
  1206         painter->setWorldTransform(QTransform());
       
  1207 
       
  1208     painter->drawPixmap(offset, pixmap);
  1296     painter->restore();
  1209     painter->restore();
  1297 }
  1210 }
  1298 
  1211 
  1299 /*!
       
  1300     \class QGraphicsBloomEffect
       
  1301     \brief The QGraphicsBloomEffect class provides a bloom/glow effect.
       
  1302     \since 4.6
       
  1303 
       
  1304     A bloom/glow effect adds fringes of light around bright areas in the source.
       
  1305 
       
  1306     \img graphicseffect-bloom.png
       
  1307 
       
  1308     \sa QGraphicsDropShadowEffect, QGraphicsBlurEffect, QGraphicsPixelizeEffect,
       
  1309         QGraphicsGrayscaleEffect, QGraphicsColorizeEffect
       
  1310 */
       
  1311 
       
  1312 /*!
       
  1313     Constructs a new QGraphicsBloomEffect instance.
       
  1314     The \a parent parameter is passed to QGraphicsEffect's constructor.
       
  1315 */
       
  1316 QGraphicsBloomEffect::QGraphicsBloomEffect(QObject *parent)
       
  1317     : QGraphicsEffect(*new QGraphicsBloomEffectPrivate, parent)
       
  1318 {
       
  1319     Q_D(QGraphicsBloomEffect);
       
  1320     for (int i = 0; i < 256; ++i)
       
  1321         d->colorTable[i] = qMin(i + d->brightness, 255);
       
  1322 }
       
  1323 
       
  1324 /*!
       
  1325     Destroys the effect.
       
  1326 */
       
  1327 QGraphicsBloomEffect::~QGraphicsBloomEffect()
       
  1328 {
       
  1329 }
       
  1330 
       
  1331 /*!
       
  1332     \reimp
       
  1333 */
       
  1334 QRectF QGraphicsBloomEffect::boundingRectFor(const QRectF &rect) const
       
  1335 {
       
  1336     Q_D(const QGraphicsBloomEffect);
       
  1337     const qreal delta = d->blurFilter.radius() * 2;
       
  1338     return rect.adjusted(-delta, -delta, delta, delta);
       
  1339 }
       
  1340 
       
  1341 /*!
       
  1342     \property QGraphicsBloomEffect::blurRadius
       
  1343     \brief the blur radius in pixels of the effect.
       
  1344 
       
  1345     Using a smaller radius results in a sharper appearance, whereas a bigger
       
  1346     radius results in a more blurred appearance.
       
  1347 
       
  1348     By default, the blur radius is 5 pixels.
       
  1349 
       
  1350     \sa strength(), brightness()
       
  1351 */
       
  1352 int QGraphicsBloomEffect::blurRadius() const
       
  1353 {
       
  1354     Q_D(const QGraphicsBloomEffect);
       
  1355     return d->blurFilter.radius();
       
  1356 }
       
  1357 
       
  1358 void QGraphicsBloomEffect::setBlurRadius(int radius)
       
  1359 {
       
  1360     Q_D(QGraphicsBloomEffect);
       
  1361     if (d->blurFilter.radius() == radius)
       
  1362         return;
       
  1363 
       
  1364     d->blurFilter.setRadius(radius);
       
  1365     updateBoundingRect();
       
  1366     emit blurRadiusChanged(radius);
       
  1367 }
       
  1368 
       
  1369 /*!
       
  1370     \fn void QGraphicsBloomEffect::blurRadiusChanged(int blurRadius)
       
  1371 
       
  1372     This signal is emitted whenever the effect's blur radius changes.
       
  1373     The \a blurRadius parameter holds the effect's new blur radius.
       
  1374 */
       
  1375 
       
  1376 /*!
       
  1377     \property QGraphicsBloomEffect::blurHint
       
  1378     \brief the blur hint of the effect.
       
  1379 
       
  1380     Use the Qt::PerformanceHint hint to say that you want a faster blur,
       
  1381     and the Qt::QualityHint hint to say that you prefer a higher quality blur.
       
  1382 
       
  1383     When animating the blur radius it's recommended to use Qt::PerformanceHint.
       
  1384 
       
  1385     By default, the blur hint is Qt::PerformanceHint.
       
  1386 */
       
  1387 Qt::RenderHint QGraphicsBloomEffect::blurHint() const
       
  1388 {
       
  1389     Q_D(const QGraphicsBloomEffect);
       
  1390     return d->blurFilter.blurHint();
       
  1391 }
       
  1392 
       
  1393 void QGraphicsBloomEffect::setBlurHint(Qt::RenderHint hint)
       
  1394 {
       
  1395     Q_D(QGraphicsBloomEffect);
       
  1396     if (d->blurFilter.blurHint() == hint)
       
  1397         return;
       
  1398 
       
  1399     d->blurFilter.setBlurHint(hint);
       
  1400     emit blurHintChanged(hint);
       
  1401 }
       
  1402 
       
  1403 /*!
       
  1404     \fn void QGraphicsBloomEffect::blurHintChanged(Qt::RenderHint hint)
       
  1405 
       
  1406     This signal is emitted whenever the effect's blur hint changes.
       
  1407     The \a hint parameter holds the effect's new blur hint.
       
  1408 */
       
  1409 
       
  1410 /*!
       
  1411     \property QGraphicsBloomEffect::brightness
       
  1412     \brief the brightness of the glow.
       
  1413 
       
  1414     The value should be in the range of 0 to 255, where 0 is dark
       
  1415     and 255 is bright.
       
  1416 
       
  1417     By default, the brightness is 70.
       
  1418 
       
  1419     \sa strength(), blurRadius()
       
  1420 */
       
  1421 int QGraphicsBloomEffect::brightness() const
       
  1422 {
       
  1423     Q_D(const QGraphicsBloomEffect);
       
  1424     return d->brightness;
       
  1425 }
       
  1426 
       
  1427 void QGraphicsBloomEffect::setBrightness(int brightness)
       
  1428 {
       
  1429     Q_D(QGraphicsBloomEffect);
       
  1430     brightness = qBound(0, brightness, 255);
       
  1431     if (d->brightness == brightness)
       
  1432         return;
       
  1433 
       
  1434     d->brightness = brightness;
       
  1435     for (int i = 0; i < 256; ++i)
       
  1436         d->colorTable[i] = qMin(i + brightness, 255);
       
  1437 
       
  1438     update();
       
  1439     emit brightnessChanged(brightness);
       
  1440 }
       
  1441 
       
  1442 /*!
       
  1443     \fn void QGraphicsBloomEffect::brightnessChanged(int brightness)
       
  1444 
       
  1445     This signal is emitted whenever the effect's brightness changes.
       
  1446     The \a brightness parameter holds the effect's new brightness.
       
  1447 */
       
  1448 
       
  1449 /*!
       
  1450     \property QGraphicsBloomEffect::strength
       
  1451     \brief the strength of the effect.
       
  1452 
       
  1453     A strength 0.0 equals to no effect, while 1.0 means maximum glow.
       
  1454 
       
  1455     By default, the strength is 0.7.
       
  1456 */
       
  1457 qreal QGraphicsBloomEffect::strength() const
       
  1458 {
       
  1459     Q_D(const QGraphicsBloomEffect);
       
  1460     return d->strength;
       
  1461 }
       
  1462 
       
  1463 void QGraphicsBloomEffect::setStrength(qreal strength)
       
  1464 {
       
  1465     Q_D(QGraphicsBloomEffect);
       
  1466     strength = qBound(qreal(0.0), strength, qreal(1.0));
       
  1467     if (qFuzzyCompare(d->strength, strength))
       
  1468         return;
       
  1469 
       
  1470     d->strength = strength;
       
  1471     update();
       
  1472     emit strengthChanged(strength);
       
  1473 }
       
  1474 
       
  1475 /*!
       
  1476     \fn void QGraphicsBloomEffect::strengthChanged(qreal strength)
       
  1477 
       
  1478     This signal is emitted whenever the effect's strength changes.
       
  1479     The \a strength parameter holds the effect's new strength.
       
  1480 */
       
  1481 
       
  1482 extern QPixmap qt_toRasterPixmap(const QPixmap &pixmap);
       
  1483 
       
  1484 /*!
       
  1485     \reimp
       
  1486 */
       
  1487 void QGraphicsBloomEffect::draw(QPainter *painter, QGraphicsEffectSource *source)
       
  1488 {
       
  1489     Q_D(QGraphicsBloomEffect);
       
  1490     if (d->strength < 0.001) {
       
  1491         source->draw(painter);
       
  1492         return;
       
  1493     }
       
  1494 
       
  1495     QPoint offset;
       
  1496     QPixmap pixmap = qt_toRasterPixmap(source->pixmap(Qt::DeviceCoordinates, &offset));
       
  1497 
       
  1498     // Blur.
       
  1499     QImage overlay(pixmap.size(), QImage::Format_ARGB32_Premultiplied);
       
  1500     overlay.fill(0);
       
  1501 
       
  1502     QPainter blurPainter(&overlay);
       
  1503     d->blurFilter.draw(&blurPainter, QPointF(), pixmap);
       
  1504     blurPainter.end();
       
  1505 
       
  1506     // Brighten.
       
  1507     const int numBits = overlay.width() * overlay.height();
       
  1508     QRgb *bits = reinterpret_cast<QRgb *>(overlay.bits());
       
  1509     for (int i = 0; i < numBits; ++i) {
       
  1510         const QRgb pixel = INV_PREMUL(bits[i]);
       
  1511         bits[i] = PREMUL(qRgba(d->colorTable[qRed(pixel)], d->colorTable[qGreen(pixel)],
       
  1512                                d->colorTable[qBlue(pixel)], qAlpha(pixel)));
       
  1513     }
       
  1514 
       
  1515     // Composite.
       
  1516     QPainter compPainter(&pixmap);
       
  1517     compPainter.setCompositionMode(QPainter::CompositionMode_Overlay);
       
  1518     compPainter.setOpacity(d->strength);
       
  1519     compPainter.drawImage(0, 0, overlay);
       
  1520     compPainter.end();
       
  1521 
       
  1522     QTransform restoreTransform = painter->worldTransform();
       
  1523     painter->setWorldTransform(QTransform());
       
  1524     painter->drawPixmap(offset, pixmap);
       
  1525     painter->setWorldTransform(restoreTransform);
       
  1526 }
       
  1527 
  1212 
  1528 QT_END_NAMESPACE
  1213 QT_END_NAMESPACE
  1529 
  1214 
       
  1215 #endif //QT_NO_GRAPHICSEFFECT