PageRenderTime 49ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/src/qt/qtbase/src/widgets/effects/qpixmapfilter.cpp

https://gitlab.com/x33n/phantomjs
C++ | 1381 lines | 766 code | 159 blank | 456 comment | 128 complexity | dcc325807d8df58504479e631d59044d MD5 | raw file
  1. /****************************************************************************
  2. **
  3. ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
  4. ** Contact: http://www.qt-project.org/legal
  5. **
  6. ** This file is part of the QtWidgets module of the Qt Toolkit.
  7. **
  8. ** $QT_BEGIN_LICENSE:LGPL$
  9. ** Commercial License Usage
  10. ** Licensees holding valid commercial Qt licenses may use this file in
  11. ** accordance with the commercial license agreement provided with the
  12. ** Software or, alternatively, in accordance with the terms contained in
  13. ** a written agreement between you and Digia. For licensing terms and
  14. ** conditions see http://qt.digia.com/licensing. For further information
  15. ** use the contact form at http://qt.digia.com/contact-us.
  16. **
  17. ** GNU Lesser General Public License Usage
  18. ** Alternatively, this file may be used under the terms of the GNU Lesser
  19. ** General Public License version 2.1 as published by the Free Software
  20. ** Foundation and appearing in the file LICENSE.LGPL included in the
  21. ** packaging of this file. Please review the following information to
  22. ** ensure the GNU Lesser General Public License version 2.1 requirements
  23. ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
  24. **
  25. ** In addition, as a special exception, Digia gives you certain additional
  26. ** rights. These rights are described in the Digia Qt LGPL Exception
  27. ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
  28. **
  29. ** GNU General Public License Usage
  30. ** Alternatively, this file may be used under the terms of the GNU
  31. ** General Public License version 3.0 as published by the Free Software
  32. ** Foundation and appearing in the file LICENSE.GPL included in the
  33. ** packaging of this file. Please review the following information to
  34. ** ensure the GNU General Public License version 3.0 requirements will be
  35. ** met: http://www.gnu.org/copyleft/gpl.html.
  36. **
  37. **
  38. ** $QT_END_LICENSE$
  39. **
  40. ****************************************************************************/
  41. #include <qglobal.h>
  42. #include <QDebug>
  43. #include "qpainter.h"
  44. #include "qpixmap.h"
  45. #include "qpixmapfilter_p.h"
  46. #include "qvarlengtharray.h"
  47. #include "private/qguiapplication_p.h"
  48. #include "private/qpaintengineex_p.h"
  49. #include "private/qpaintengine_raster_p.h"
  50. #include "qmath.h"
  51. #include "private/qmath_p.h"
  52. #include "private/qmemrotate_p.h"
  53. #include "private/qdrawhelper_p.h"
  54. #ifndef QT_NO_GRAPHICSEFFECT
  55. QT_BEGIN_NAMESPACE
  56. class QPixmapFilterPrivate : public QObjectPrivate
  57. {
  58. Q_DECLARE_PUBLIC(QPixmapFilter)
  59. public:
  60. QPixmapFilter::FilterType type;
  61. };
  62. /*!
  63. \class QPixmapFilter
  64. \since 4.5
  65. \ingroup painting
  66. \brief The QPixmapFilter class provides the basic functionality for
  67. pixmap filter classes. Pixmap filter can be for example colorize or blur.
  68. QPixmapFilter is the base class for every pixmap filter. QPixmapFilter is
  69. an abstract class and cannot itself be instantiated. It provides a standard
  70. interface for filter processing.
  71. \internal
  72. */
  73. /*!
  74. \enum QPixmapFilter::FilterType
  75. \internal
  76. This enum describes the types of filter that can be applied to pixmaps.
  77. \value ConvolutionFilter A filter that is used to calculate the convolution
  78. of the image with a kernel. See
  79. QPixmapConvolutionFilter for more information.
  80. \value ColorizeFilter A filter that is used to change the overall color
  81. of an image. See QPixmapColorizeFilter for more
  82. information.
  83. \value DropShadowFilter A filter that is used to add a drop shadow to an
  84. image. See QPixmapDropShadowFilter for more
  85. information.
  86. \value BlurFilter A filter that is used to blur an image using
  87. a simple blur radius. See QPixmapBlurFilter
  88. for more information.
  89. \value UserFilter The first filter type that can be used for
  90. application-specific purposes.
  91. */
  92. /*!
  93. Constructs a default QPixmapFilter with the given \a type.
  94. This constructor should be used when subclassing QPixmapFilter to
  95. create custom user filters.
  96. \internal
  97. */
  98. QPixmapFilter::QPixmapFilter(FilterType type, QObject *parent)
  99. : QObject(*new QPixmapFilterPrivate, parent)
  100. {
  101. d_func()->type = type;
  102. }
  103. /*!
  104. \internal
  105. */
  106. QPixmapFilter::QPixmapFilter(QPixmapFilterPrivate&d, QPixmapFilter::FilterType type, QObject *parent)
  107. : QObject(d, parent)
  108. {
  109. d_func()->type = type;
  110. }
  111. /*!
  112. Destroys the pixmap filter.
  113. \internal
  114. */
  115. QPixmapFilter::~QPixmapFilter()
  116. {
  117. }
  118. /*!
  119. Returns the type of the filter. All standard pixmap filter classes
  120. are associated with a unique value.
  121. \internal
  122. */
  123. QPixmapFilter::FilterType QPixmapFilter::type() const
  124. {
  125. Q_D(const QPixmapFilter);
  126. return d->type;
  127. }
  128. /*!
  129. Returns the bounding rectangle that is affected by the pixmap
  130. filter if the filter is applied to the specified \a rect.
  131. \internal
  132. */
  133. QRectF QPixmapFilter::boundingRectFor(const QRectF &rect) const
  134. {
  135. return rect;
  136. }
  137. /*!
  138. \fn void QPixmapFilter::draw(QPainter *painter, const QPointF &p, const QPixmap &src, const QRectF& srcRect) const
  139. Uses \a painter to draw filtered result of \a src at the point
  140. specified by \a p. If \a srcRect is specified the it will
  141. be used as a source rectangle to only draw a part of the source.
  142. draw() will affect the area which boundingRectFor() returns.
  143. \internal
  144. */
  145. /*!
  146. \class QPixmapConvolutionFilter
  147. \since 4.5
  148. \ingroup painting
  149. \brief The QPixmapConvolutionFilter class provides convolution
  150. filtering for pixmaps.
  151. QPixmapConvolutionFilter implements a convolution pixmap filter,
  152. which is applied when \l{QPixmapFilter::}{draw()} is called. A
  153. convolution filter lets you distort an image by setting the values
  154. of a matrix of qreal values called its
  155. \l{setConvolutionKernel()}{kernel}. The matrix's values are
  156. usually between -1.0 and 1.0.
  157. \omit
  158. In convolution filtering, the pixel value is calculated from the
  159. neighboring pixels based on the weighting convolution kernel.
  160. This needs explaining to be useful.
  161. \endomit
  162. Example:
  163. \snippet code/src_gui_image_qpixmapfilter.cpp 1
  164. \sa {Pixmap Filters Example}, QPixmapColorizeFilter, QPixmapDropShadowFilter
  165. \internal
  166. */
  167. class QPixmapConvolutionFilterPrivate : public QPixmapFilterPrivate
  168. {
  169. public:
  170. QPixmapConvolutionFilterPrivate(): convolutionKernel(0), kernelWidth(0), kernelHeight(0), convoluteAlpha(false) {}
  171. ~QPixmapConvolutionFilterPrivate() {
  172. delete[] convolutionKernel;
  173. }
  174. qreal *convolutionKernel;
  175. int kernelWidth;
  176. int kernelHeight;
  177. bool convoluteAlpha;
  178. };
  179. /*!
  180. Constructs a pixmap convolution filter.
  181. By default there is no convolution kernel.
  182. \internal
  183. */
  184. QPixmapConvolutionFilter::QPixmapConvolutionFilter(QObject *parent)
  185. : QPixmapFilter(*new QPixmapConvolutionFilterPrivate, ConvolutionFilter, parent)
  186. {
  187. Q_D(QPixmapConvolutionFilter);
  188. d->convoluteAlpha = true;
  189. }
  190. /*!
  191. Destructor of pixmap convolution filter.
  192. \internal
  193. */
  194. QPixmapConvolutionFilter::~QPixmapConvolutionFilter()
  195. {
  196. }
  197. /*!
  198. Sets convolution kernel with the given number of \a rows and \a columns.
  199. Values from \a kernel are copied to internal data structure.
  200. To preserve the intensity of the pixmap, the sum of all the
  201. values in the convolution kernel should add up to 1.0. A sum
  202. greater than 1.0 produces a lighter result and a sum less than 1.0
  203. produces a darker and transparent result.
  204. \internal
  205. */
  206. void QPixmapConvolutionFilter::setConvolutionKernel(const qreal *kernel, int rows, int columns)
  207. {
  208. Q_D(QPixmapConvolutionFilter);
  209. delete [] d->convolutionKernel;
  210. d->convolutionKernel = new qreal[rows * columns];
  211. memcpy(d->convolutionKernel, kernel, sizeof(qreal) * rows * columns);
  212. d->kernelWidth = columns;
  213. d->kernelHeight = rows;
  214. }
  215. /*!
  216. Gets the convolution kernel data.
  217. \internal
  218. */
  219. const qreal *QPixmapConvolutionFilter::convolutionKernel() const
  220. {
  221. Q_D(const QPixmapConvolutionFilter);
  222. return d->convolutionKernel;
  223. }
  224. /*!
  225. Gets the number of rows in the convolution kernel.
  226. \internal
  227. */
  228. int QPixmapConvolutionFilter::rows() const
  229. {
  230. Q_D(const QPixmapConvolutionFilter);
  231. return d->kernelHeight;
  232. }
  233. /*!
  234. Gets the number of columns in the convolution kernel.
  235. \internal
  236. */
  237. int QPixmapConvolutionFilter::columns() const
  238. {
  239. Q_D(const QPixmapConvolutionFilter);
  240. return d->kernelWidth;
  241. }
  242. /*!
  243. \internal
  244. */
  245. QRectF QPixmapConvolutionFilter::boundingRectFor(const QRectF &rect) const
  246. {
  247. Q_D(const QPixmapConvolutionFilter);
  248. return rect.adjusted(-d->kernelWidth / 2, -d->kernelHeight / 2, (d->kernelWidth - 1) / 2, (d->kernelHeight - 1) / 2);
  249. }
  250. // Convolutes the image
  251. static void convolute(
  252. QImage *destImage,
  253. const QPointF &pos,
  254. const QImage &srcImage,
  255. const QRectF &srcRect,
  256. QPainter::CompositionMode mode,
  257. qreal *kernel,
  258. int kernelWidth,
  259. int kernelHeight )
  260. {
  261. const QImage processImage = (srcImage.format() != QImage::Format_ARGB32_Premultiplied ) ? srcImage.convertToFormat(QImage::Format_ARGB32_Premultiplied) : srcImage;
  262. // TODO: support also other formats directly without copying
  263. int *fixedKernel = new int[kernelWidth*kernelHeight];
  264. for(int i = 0; i < kernelWidth*kernelHeight; i++)
  265. {
  266. fixedKernel[i] = (int)(65536 * kernel[i]);
  267. }
  268. QRectF trect = srcRect.isNull() ? processImage.rect() : srcRect;
  269. trect.moveTo(pos);
  270. QRectF bounded = trect.adjusted(-kernelWidth / 2, -kernelHeight / 2, (kernelWidth - 1) / 2, (kernelHeight - 1) / 2);
  271. QRect rect = bounded.toAlignedRect();
  272. QRect targetRect = rect.intersected(destImage->rect());
  273. QRectF srect = srcRect.isNull() ? processImage.rect() : srcRect;
  274. QRectF sbounded = srect.adjusted(-kernelWidth / 2, -kernelHeight / 2, (kernelWidth - 1) / 2, (kernelHeight - 1) / 2);
  275. QPoint srcStartPoint = sbounded.toAlignedRect().topLeft()+(targetRect.topLeft()-rect.topLeft());
  276. const uint *sourceStart = (uint*)processImage.scanLine(0);
  277. uint *outputStart = (uint*)destImage->scanLine(0);
  278. int yk = srcStartPoint.y();
  279. for (int y = targetRect.top(); y <= targetRect.bottom(); y++) {
  280. uint* output = outputStart + (destImage->bytesPerLine()/sizeof(uint))*y+targetRect.left();
  281. int xk = srcStartPoint.x();
  282. for(int x = targetRect.left(); x <= targetRect.right(); x++) {
  283. int r = 0;
  284. int g = 0;
  285. int b = 0;
  286. int a = 0;
  287. // some out of bounds pre-checking to avoid inner-loop ifs
  288. int kernely = -kernelHeight/2;
  289. int starty = 0;
  290. int endy = kernelHeight;
  291. if(yk+kernely+endy >= srcImage.height())
  292. endy = kernelHeight-((yk+kernely+endy)-srcImage.height())-1;
  293. if(yk+kernely < 0)
  294. starty = -(yk+kernely);
  295. int kernelx = -kernelWidth/2;
  296. int startx = 0;
  297. int endx = kernelWidth;
  298. if(xk+kernelx+endx >= srcImage.width())
  299. endx = kernelWidth-((xk+kernelx+endx)-srcImage.width())-1;
  300. if(xk+kernelx < 0)
  301. startx = -(xk+kernelx);
  302. for (int ys = starty; ys < endy; ys ++) {
  303. const uint *pix = sourceStart + (processImage.bytesPerLine()/sizeof(uint))*(yk+kernely+ys) + ((xk+kernelx+startx));
  304. const uint *endPix = pix+endx-startx;
  305. int kernelPos = ys*kernelWidth+startx;
  306. while (pix < endPix) {
  307. int factor = fixedKernel[kernelPos++];
  308. a += (((*pix) & 0xff000000)>>24) * factor;
  309. r += (((*pix) & 0x00ff0000)>>16) * factor;
  310. g += (((*pix) & 0x0000ff00)>>8 ) * factor;
  311. b += (((*pix) & 0x000000ff) ) * factor;
  312. pix++;
  313. }
  314. }
  315. r = qBound((int)0, r >> 16, (int)255);
  316. g = qBound((int)0, g >> 16, (int)255);
  317. b = qBound((int)0, b >> 16, (int)255);
  318. a = qBound((int)0, a >> 16, (int)255);
  319. // composition mode checking could be moved outside of loop
  320. if(mode == QPainter::CompositionMode_Source) {
  321. uint color = (a<<24)+(r<<16)+(g<<8)+b;
  322. *output++ = color;
  323. } else {
  324. uint current = *output;
  325. uchar ca = (current&0xff000000)>>24;
  326. uchar cr = (current&0x00ff0000)>>16;
  327. uchar cg = (current&0x0000ff00)>>8;
  328. uchar cb = (current&0x000000ff);
  329. uint color =
  330. (((ca*(255-a) >> 8)+a) << 24)+
  331. (((cr*(255-a) >> 8)+r) << 16)+
  332. (((cg*(255-a) >> 8)+g) << 8)+
  333. (((cb*(255-a) >> 8)+b));
  334. *output++ = color;;
  335. }
  336. xk++;
  337. }
  338. yk++;
  339. }
  340. delete[] fixedKernel;
  341. }
  342. /*!
  343. \internal
  344. */
  345. void QPixmapConvolutionFilter::draw(QPainter *painter, const QPointF &p, const QPixmap &src, const QRectF& srcRect) const
  346. {
  347. Q_D(const QPixmapConvolutionFilter);
  348. if (!painter->isActive())
  349. return;
  350. if(d->kernelWidth<=0 || d->kernelHeight <= 0)
  351. return;
  352. if (src.isNull())
  353. return;
  354. QPixmapFilter *filter = painter->paintEngine() && painter->paintEngine()->isExtended() ?
  355. static_cast<QPaintEngineEx *>(painter->paintEngine())->pixmapFilter(type(), this) : 0;
  356. QPixmapConvolutionFilter *convolutionFilter = static_cast<QPixmapConvolutionFilter*>(filter);
  357. if (convolutionFilter) {
  358. convolutionFilter->setConvolutionKernel(d->convolutionKernel, d->kernelWidth, d->kernelHeight);
  359. convolutionFilter->d_func()->convoluteAlpha = d->convoluteAlpha;
  360. convolutionFilter->draw(painter, p, src, srcRect);
  361. return;
  362. }
  363. // falling back to raster implementation
  364. QImage *target = 0;
  365. if (painter->paintEngine()->paintDevice()->devType() == QInternal::Image) {
  366. target = static_cast<QImage *>(painter->paintEngine()->paintDevice());
  367. QTransform mat = painter->combinedTransform();
  368. if (mat.type() > QTransform::TxTranslate) {
  369. // Disabled because of transformation...
  370. target = 0;
  371. } else {
  372. QRasterPaintEngine *pe = static_cast<QRasterPaintEngine *>(painter->paintEngine());
  373. if (pe->clipType() == QRasterPaintEngine::ComplexClip)
  374. // disabled because of complex clipping...
  375. target = 0;
  376. else {
  377. QRectF clip = pe->clipBoundingRect();
  378. QRectF rect = boundingRectFor(srcRect.isEmpty() ? src.rect() : srcRect);
  379. QTransform x = painter->deviceTransform();
  380. if (!clip.contains(rect.translated(x.dx() + p.x(), x.dy() + p.y()))) {
  381. target = 0;
  382. }
  383. }
  384. }
  385. }
  386. if (target) {
  387. QTransform x = painter->deviceTransform();
  388. QPointF offset(x.dx(), x.dy());
  389. convolute(target, p+offset, src.toImage(), srcRect, QPainter::CompositionMode_SourceOver, d->convolutionKernel, d->kernelWidth, d->kernelHeight);
  390. } else {
  391. QRect srect = srcRect.isNull() ? src.rect() : srcRect.toRect();
  392. QRect rect = boundingRectFor(srect).toRect();
  393. QImage result = QImage(rect.size(), QImage::Format_ARGB32_Premultiplied);
  394. QPoint offset = srect.topLeft() - rect.topLeft();
  395. convolute(&result,
  396. offset,
  397. src.toImage(),
  398. srect,
  399. QPainter::CompositionMode_Source,
  400. d->convolutionKernel,
  401. d->kernelWidth,
  402. d->kernelHeight);
  403. painter->drawImage(p - offset, result);
  404. }
  405. }
  406. /*!
  407. \class QPixmapBlurFilter
  408. \since 4.6
  409. \ingroup multimedia
  410. \brief The QPixmapBlurFilter class provides blur filtering
  411. for pixmaps.
  412. QPixmapBlurFilter implements a blur pixmap filter,
  413. which is applied when \l{QPixmapFilter::}{draw()} is called.
  414. The filter lets you specialize the radius of the blur as well
  415. as hints as to whether to prefer performance or quality.
  416. By default, the blur effect is produced by applying an exponential
  417. filter generated from the specified blurRadius(). Paint engines
  418. may override this with a custom blur that is faster on the
  419. underlying hardware.
  420. \sa {Pixmap Filters Example}, QPixmapConvolutionFilter, QPixmapDropShadowFilter
  421. \internal
  422. */
  423. class QPixmapBlurFilterPrivate : public QPixmapFilterPrivate
  424. {
  425. public:
  426. QPixmapBlurFilterPrivate() : radius(5), hints(QGraphicsBlurEffect::PerformanceHint) {}
  427. qreal radius;
  428. QGraphicsBlurEffect::BlurHints hints;
  429. };
  430. /*!
  431. Constructs a pixmap blur filter.
  432. \internal
  433. */
  434. QPixmapBlurFilter::QPixmapBlurFilter(QObject *parent)
  435. : QPixmapFilter(*new QPixmapBlurFilterPrivate, BlurFilter, parent)
  436. {
  437. }
  438. /*!
  439. Destructor of pixmap blur filter.
  440. \internal
  441. */
  442. QPixmapBlurFilter::~QPixmapBlurFilter()
  443. {
  444. }
  445. /*!
  446. Sets the radius of the blur filter. Higher radius produces increased blurriness.
  447. \internal
  448. */
  449. void QPixmapBlurFilter::setRadius(qreal radius)
  450. {
  451. Q_D(QPixmapBlurFilter);
  452. d->radius = radius;
  453. }
  454. /*!
  455. Gets the radius of the blur filter.
  456. \internal
  457. */
  458. qreal QPixmapBlurFilter::radius() const
  459. {
  460. Q_D(const QPixmapBlurFilter);
  461. return d->radius;
  462. }
  463. /*!
  464. Setting the blur hints to PerformanceHint causes the implementation
  465. to trade off visual quality to blur the image faster. Setting the
  466. blur hints to QualityHint causes the implementation to improve
  467. visual quality at the expense of speed.
  468. AnimationHint causes the implementation to optimize for animating
  469. the blur radius, possibly by caching blurred versions of the source
  470. pixmap.
  471. The implementation is free to ignore this value if it only has a single
  472. blur algorithm.
  473. \internal
  474. */
  475. void QPixmapBlurFilter::setBlurHints(QGraphicsBlurEffect::BlurHints hints)
  476. {
  477. Q_D(QPixmapBlurFilter);
  478. d->hints = hints;
  479. }
  480. /*!
  481. Gets the blur hints of the blur filter.
  482. \internal
  483. */
  484. QGraphicsBlurEffect::BlurHints QPixmapBlurFilter::blurHints() const
  485. {
  486. Q_D(const QPixmapBlurFilter);
  487. return d->hints;
  488. }
  489. const qreal radiusScale = qreal(2.5);
  490. /*!
  491. \internal
  492. */
  493. QRectF QPixmapBlurFilter::boundingRectFor(const QRectF &rect) const
  494. {
  495. Q_D(const QPixmapBlurFilter);
  496. const qreal delta = radiusScale * d->radius + 1;
  497. return rect.adjusted(-delta, -delta, delta, delta);
  498. }
  499. template <int shift>
  500. inline int qt_static_shift(int value)
  501. {
  502. if (shift == 0)
  503. return value;
  504. else if (shift > 0)
  505. return value << (uint(shift) & 0x1f);
  506. else
  507. return value >> (uint(-shift) & 0x1f);
  508. }
  509. template<int aprec, int zprec>
  510. inline void qt_blurinner(uchar *bptr, int &zR, int &zG, int &zB, int &zA, int alpha)
  511. {
  512. QRgb *pixel = (QRgb *)bptr;
  513. #define Z_MASK (0xff << zprec)
  514. const int A_zprec = qt_static_shift<zprec - 24>(*pixel) & Z_MASK;
  515. const int R_zprec = qt_static_shift<zprec - 16>(*pixel) & Z_MASK;
  516. const int G_zprec = qt_static_shift<zprec - 8>(*pixel) & Z_MASK;
  517. const int B_zprec = qt_static_shift<zprec>(*pixel) & Z_MASK;
  518. #undef Z_MASK
  519. const int zR_zprec = zR >> aprec;
  520. const int zG_zprec = zG >> aprec;
  521. const int zB_zprec = zB >> aprec;
  522. const int zA_zprec = zA >> aprec;
  523. zR += alpha * (R_zprec - zR_zprec);
  524. zG += alpha * (G_zprec - zG_zprec);
  525. zB += alpha * (B_zprec - zB_zprec);
  526. zA += alpha * (A_zprec - zA_zprec);
  527. #define ZA_MASK (0xff << (zprec + aprec))
  528. *pixel =
  529. qt_static_shift<24 - zprec - aprec>(zA & ZA_MASK)
  530. | qt_static_shift<16 - zprec - aprec>(zR & ZA_MASK)
  531. | qt_static_shift<8 - zprec - aprec>(zG & ZA_MASK)
  532. | qt_static_shift<-zprec - aprec>(zB & ZA_MASK);
  533. #undef ZA_MASK
  534. }
  535. const int alphaIndex = (QSysInfo::ByteOrder == QSysInfo::BigEndian ? 0 : 3);
  536. template<int aprec, int zprec>
  537. inline void qt_blurinner_alphaOnly(uchar *bptr, int &z, int alpha)
  538. {
  539. const int A_zprec = int(*(bptr)) << zprec;
  540. const int z_zprec = z >> aprec;
  541. z += alpha * (A_zprec - z_zprec);
  542. *(bptr) = z >> (zprec + aprec);
  543. }
  544. template<int aprec, int zprec, bool alphaOnly>
  545. inline void qt_blurrow(QImage & im, int line, int alpha)
  546. {
  547. uchar *bptr = im.scanLine(line);
  548. int zR = 0, zG = 0, zB = 0, zA = 0;
  549. if (alphaOnly && im.format() != QImage::Format_Indexed8)
  550. bptr += alphaIndex;
  551. const int stride = im.depth() >> 3;
  552. const int im_width = im.width();
  553. for (int index = 0; index < im_width; ++index) {
  554. if (alphaOnly)
  555. qt_blurinner_alphaOnly<aprec, zprec>(bptr, zA, alpha);
  556. else
  557. qt_blurinner<aprec, zprec>(bptr, zR, zG, zB, zA, alpha);
  558. bptr += stride;
  559. }
  560. bptr -= stride;
  561. for (int index = im_width - 2; index >= 0; --index) {
  562. bptr -= stride;
  563. if (alphaOnly)
  564. qt_blurinner_alphaOnly<aprec, zprec>(bptr, zA, alpha);
  565. else
  566. qt_blurinner<aprec, zprec>(bptr, zR, zG, zB, zA, alpha);
  567. }
  568. }
  569. /*
  570. * expblur(QImage &img, int radius)
  571. *
  572. * Based on exponential blur algorithm by Jani Huhtanen
  573. *
  574. * In-place blur of image 'img' with kernel
  575. * of approximate radius 'radius'.
  576. *
  577. * Blurs with two sided exponential impulse
  578. * response.
  579. *
  580. * aprec = precision of alpha parameter
  581. * in fixed-point format 0.aprec
  582. *
  583. * zprec = precision of state parameters
  584. * zR,zG,zB and zA in fp format 8.zprec
  585. */
  586. template <int aprec, int zprec, bool alphaOnly>
  587. void expblur(QImage &img, qreal radius, bool improvedQuality = false, int transposed = 0)
  588. {
  589. // halve the radius if we're using two passes
  590. if (improvedQuality)
  591. radius *= qreal(0.5);
  592. Q_ASSERT(img.format() == QImage::Format_ARGB32_Premultiplied
  593. || img.format() == QImage::Format_RGB32
  594. || img.format() == QImage::Format_Indexed8);
  595. // choose the alpha such that pixels at radius distance from a fully
  596. // saturated pixel will have an alpha component of no greater than
  597. // the cutOffIntensity
  598. const qreal cutOffIntensity = 2;
  599. int alpha = radius <= qreal(1e-5)
  600. ? ((1 << aprec)-1)
  601. : qRound((1<<aprec)*(1 - qPow(cutOffIntensity * (1 / qreal(255)), 1 / radius)));
  602. int img_height = img.height();
  603. for (int row = 0; row < img_height; ++row) {
  604. for (int i = 0; i <= int(improvedQuality); ++i)
  605. qt_blurrow<aprec, zprec, alphaOnly>(img, row, alpha);
  606. }
  607. QImage temp(img.height(), img.width(), img.format());
  608. if (transposed >= 0) {
  609. if (img.depth() == 8) {
  610. qt_memrotate270(reinterpret_cast<const quint8*>(img.bits()),
  611. img.width(), img.height(), img.bytesPerLine(),
  612. reinterpret_cast<quint8*>(temp.bits()),
  613. temp.bytesPerLine());
  614. } else {
  615. qt_memrotate270(reinterpret_cast<const quint32*>(img.bits()),
  616. img.width(), img.height(), img.bytesPerLine(),
  617. reinterpret_cast<quint32*>(temp.bits()),
  618. temp.bytesPerLine());
  619. }
  620. } else {
  621. if (img.depth() == 8) {
  622. qt_memrotate90(reinterpret_cast<const quint8*>(img.bits()),
  623. img.width(), img.height(), img.bytesPerLine(),
  624. reinterpret_cast<quint8*>(temp.bits()),
  625. temp.bytesPerLine());
  626. } else {
  627. qt_memrotate90(reinterpret_cast<const quint32*>(img.bits()),
  628. img.width(), img.height(), img.bytesPerLine(),
  629. reinterpret_cast<quint32*>(temp.bits()),
  630. temp.bytesPerLine());
  631. }
  632. }
  633. img_height = temp.height();
  634. for (int row = 0; row < img_height; ++row) {
  635. for (int i = 0; i <= int(improvedQuality); ++i)
  636. qt_blurrow<aprec, zprec, alphaOnly>(temp, row, alpha);
  637. }
  638. if (transposed == 0) {
  639. if (img.depth() == 8) {
  640. qt_memrotate90(reinterpret_cast<const quint8*>(temp.bits()),
  641. temp.width(), temp.height(), temp.bytesPerLine(),
  642. reinterpret_cast<quint8*>(img.bits()),
  643. img.bytesPerLine());
  644. } else {
  645. qt_memrotate90(reinterpret_cast<const quint32*>(temp.bits()),
  646. temp.width(), temp.height(), temp.bytesPerLine(),
  647. reinterpret_cast<quint32*>(img.bits()),
  648. img.bytesPerLine());
  649. }
  650. } else {
  651. img = temp;
  652. }
  653. }
  654. #define AVG(a,b) ( ((((a)^(b)) & 0xfefefefeUL) >> 1) + ((a)&(b)) )
  655. #define AVG16(a,b) ( ((((a)^(b)) & 0xf7deUL) >> 1) + ((a)&(b)) )
  656. Q_WIDGETS_EXPORT QImage qt_halfScaled(const QImage &source)
  657. {
  658. if (source.width() < 2 || source.height() < 2)
  659. return QImage();
  660. QImage srcImage = source;
  661. if (source.format() == QImage::Format_Indexed8) {
  662. // assumes grayscale
  663. QImage dest(source.width() / 2, source.height() / 2, srcImage.format());
  664. const uchar *src = reinterpret_cast<const uchar*>(const_cast<const QImage &>(srcImage).bits());
  665. int sx = srcImage.bytesPerLine();
  666. int sx2 = sx << 1;
  667. uchar *dst = reinterpret_cast<uchar*>(dest.bits());
  668. int dx = dest.bytesPerLine();
  669. int ww = dest.width();
  670. int hh = dest.height();
  671. for (int y = hh; y; --y, dst += dx, src += sx2) {
  672. const uchar *p1 = src;
  673. const uchar *p2 = src + sx;
  674. uchar *q = dst;
  675. for (int x = ww; x; --x, ++q, p1 += 2, p2 += 2)
  676. *q = ((int(p1[0]) + int(p1[1]) + int(p2[0]) + int(p2[1])) + 2) >> 2;
  677. }
  678. return dest;
  679. } else if (source.format() == QImage::Format_ARGB8565_Premultiplied) {
  680. QImage dest(source.width() / 2, source.height() / 2, srcImage.format());
  681. const uchar *src = reinterpret_cast<const uchar*>(const_cast<const QImage &>(srcImage).bits());
  682. int sx = srcImage.bytesPerLine();
  683. int sx2 = sx << 1;
  684. uchar *dst = reinterpret_cast<uchar*>(dest.bits());
  685. int dx = dest.bytesPerLine();
  686. int ww = dest.width();
  687. int hh = dest.height();
  688. for (int y = hh; y; --y, dst += dx, src += sx2) {
  689. const uchar *p1 = src;
  690. const uchar *p2 = src + sx;
  691. uchar *q = dst;
  692. for (int x = ww; x; --x, q += 3, p1 += 6, p2 += 6) {
  693. // alpha
  694. q[0] = AVG(AVG(p1[0], p1[3]), AVG(p2[0], p2[3]));
  695. // rgb
  696. const quint16 p16_1 = (p1[2] << 8) | p1[1];
  697. const quint16 p16_2 = (p1[5] << 8) | p1[4];
  698. const quint16 p16_3 = (p2[2] << 8) | p2[1];
  699. const quint16 p16_4 = (p2[5] << 8) | p2[4];
  700. const quint16 result = AVG16(AVG16(p16_1, p16_2), AVG16(p16_3, p16_4));
  701. q[1] = result & 0xff;
  702. q[2] = result >> 8;
  703. }
  704. }
  705. return dest;
  706. } else if (source.format() != QImage::Format_ARGB32_Premultiplied
  707. && source.format() != QImage::Format_RGB32)
  708. {
  709. srcImage = source.convertToFormat(QImage::Format_ARGB32_Premultiplied);
  710. }
  711. QImage dest(source.width() / 2, source.height() / 2, srcImage.format());
  712. const quint32 *src = reinterpret_cast<const quint32*>(const_cast<const QImage &>(srcImage).bits());
  713. int sx = srcImage.bytesPerLine() >> 2;
  714. int sx2 = sx << 1;
  715. quint32 *dst = reinterpret_cast<quint32*>(dest.bits());
  716. int dx = dest.bytesPerLine() >> 2;
  717. int ww = dest.width();
  718. int hh = dest.height();
  719. for (int y = hh; y; --y, dst += dx, src += sx2) {
  720. const quint32 *p1 = src;
  721. const quint32 *p2 = src + sx;
  722. quint32 *q = dst;
  723. for (int x = ww; x; --x, q++, p1 += 2, p2 += 2)
  724. *q = AVG(AVG(p1[0], p1[1]), AVG(p2[0], p2[1]));
  725. }
  726. return dest;
  727. }
  728. Q_WIDGETS_EXPORT void qt_blurImage(QPainter *p, QImage &blurImage, qreal radius, bool quality, bool alphaOnly, int transposed = 0)
  729. {
  730. if (blurImage.format() != QImage::Format_ARGB32_Premultiplied
  731. && blurImage.format() != QImage::Format_RGB32)
  732. {
  733. blurImage = blurImage.convertToFormat(QImage::Format_ARGB32_Premultiplied);
  734. }
  735. qreal scale = 1;
  736. if (radius >= 4 && blurImage.width() >= 2 && blurImage.height() >= 2) {
  737. blurImage = qt_halfScaled(blurImage);
  738. scale = 2;
  739. radius *= qreal(0.5);
  740. }
  741. if (alphaOnly)
  742. expblur<12, 10, true>(blurImage, radius, quality, transposed);
  743. else
  744. expblur<12, 10, false>(blurImage, radius, quality, transposed);
  745. if (p) {
  746. p->scale(scale, scale);
  747. p->setRenderHint(QPainter::SmoothPixmapTransform);
  748. p->drawImage(QRect(0, 0, blurImage.width(), blurImage.height()), blurImage);
  749. }
  750. }
  751. Q_WIDGETS_EXPORT void qt_blurImage(QImage &blurImage, qreal radius, bool quality, int transposed = 0)
  752. {
  753. if (blurImage.format() == QImage::Format_Indexed8)
  754. expblur<12, 10, true>(blurImage, radius, quality, transposed);
  755. else
  756. expblur<12, 10, false>(blurImage, radius, quality, transposed);
  757. }
  758. Q_GUI_EXPORT extern bool qt_scaleForTransform(const QTransform &transform, qreal *scale);
  759. /*!
  760. \internal
  761. */
  762. void QPixmapBlurFilter::draw(QPainter *painter, const QPointF &p, const QPixmap &src, const QRectF &rect) const
  763. {
  764. Q_D(const QPixmapBlurFilter);
  765. if (!painter->isActive())
  766. return;
  767. if (src.isNull())
  768. return;
  769. QRectF srcRect = rect;
  770. if (srcRect.isNull())
  771. srcRect = src.rect();
  772. if (d->radius <= 1) {
  773. painter->drawPixmap(srcRect.translated(p), src, srcRect);
  774. return;
  775. }
  776. qreal scaledRadius = radiusScale * d->radius;
  777. qreal scale;
  778. if (qt_scaleForTransform(painter->transform(), &scale))
  779. scaledRadius /= scale;
  780. QPixmapFilter *filter = painter->paintEngine() && painter->paintEngine()->isExtended() ?
  781. static_cast<QPaintEngineEx *>(painter->paintEngine())->pixmapFilter(type(), this) : 0;
  782. QPixmapBlurFilter *blurFilter = static_cast<QPixmapBlurFilter*>(filter);
  783. if (blurFilter) {
  784. blurFilter->setRadius(scaledRadius);
  785. blurFilter->setBlurHints(d->hints);
  786. blurFilter->draw(painter, p, src, srcRect);
  787. return;
  788. }
  789. QImage srcImage;
  790. QImage destImage;
  791. if (srcRect == src.rect()) {
  792. srcImage = src.toImage();
  793. } else {
  794. QRect rect = srcRect.toAlignedRect().intersected(src.rect());
  795. srcImage = src.copy(rect).toImage();
  796. }
  797. QTransform transform = painter->worldTransform();
  798. painter->translate(p);
  799. qt_blurImage(painter, srcImage, scaledRadius, (d->hints & QGraphicsBlurEffect::QualityHint), false);
  800. painter->setWorldTransform(transform);
  801. }
  802. // grayscales the image to dest (could be same). If rect isn't defined
  803. // destination image size is used to determine the dimension of grayscaling
  804. // process.
  805. static void grayscale(const QImage &image, QImage &dest, const QRect& rect = QRect())
  806. {
  807. QRect destRect = rect;
  808. QRect srcRect = rect;
  809. if (rect.isNull()) {
  810. srcRect = dest.rect();
  811. destRect = dest.rect();
  812. }
  813. if (&image != &dest) {
  814. destRect.moveTo(QPoint(0, 0));
  815. }
  816. unsigned int *data = (unsigned int *)image.bits();
  817. unsigned int *outData = (unsigned int *)dest.bits();
  818. if (dest.size() == image.size() && image.rect() == srcRect) {
  819. // a bit faster loop for grayscaling everything
  820. int pixels = dest.width() * dest.height();
  821. for (int i = 0; i < pixels; ++i) {
  822. int val = qGray(data[i]);
  823. outData[i] = qRgba(val, val, val, qAlpha(data[i]));
  824. }
  825. } else {
  826. int yd = destRect.top();
  827. for (int y = srcRect.top(); y <= srcRect.bottom() && y < image.height(); y++) {
  828. data = (unsigned int*)image.scanLine(y);
  829. outData = (unsigned int*)dest.scanLine(yd++);
  830. int xd = destRect.left();
  831. for (int x = srcRect.left(); x <= srcRect.right() && x < image.width(); x++) {
  832. int val = qGray(data[x]);
  833. outData[xd++] = qRgba(val, val, val, qAlpha(data[x]));
  834. }
  835. }
  836. }
  837. }
  838. /*!
  839. \class QPixmapColorizeFilter
  840. \since 4.5
  841. \ingroup painting
  842. \brief The QPixmapColorizeFilter class provides colorizing
  843. filtering for pixmaps.
  844. A colorize filter gives the pixmap a tint of its color(). The
  845. filter first grayscales the pixmap and then converts those to
  846. colorized values using QPainter::CompositionMode_Screen with the
  847. chosen color. The alpha-channel is not changed.
  848. Example:
  849. \snippet code/src_gui_image_qpixmapfilter.cpp 0
  850. \sa QPainter::CompositionMode
  851. \internal
  852. */
  853. class QPixmapColorizeFilterPrivate : public QPixmapFilterPrivate
  854. {
  855. Q_DECLARE_PUBLIC(QPixmapColorizeFilter)
  856. public:
  857. QColor color;
  858. qreal strength;
  859. quint32 opaque : 1;
  860. quint32 alphaBlend : 1;
  861. quint32 padding : 30;
  862. };
  863. /*!
  864. Constructs an pixmap colorize filter.
  865. Default color value for colorizing is QColor(0, 0, 192).
  866. \internal
  867. */
  868. QPixmapColorizeFilter::QPixmapColorizeFilter(QObject *parent)
  869. : QPixmapFilter(*new QPixmapColorizeFilterPrivate, ColorizeFilter, parent)
  870. {
  871. Q_D(QPixmapColorizeFilter);
  872. d->color = QColor(0, 0, 192);
  873. d->strength = qreal(1);
  874. d->opaque = true;
  875. d->alphaBlend = false;
  876. }
  877. /*!
  878. Gets the color of the colorize filter.
  879. \internal
  880. */
  881. QColor QPixmapColorizeFilter::color() const
  882. {
  883. Q_D(const QPixmapColorizeFilter);
  884. return d->color;
  885. }
  886. /*!
  887. Sets the color of the colorize filter to the \a color specified.
  888. \internal
  889. */
  890. void QPixmapColorizeFilter::setColor(const QColor &color)
  891. {
  892. Q_D(QPixmapColorizeFilter);
  893. d->color = color;
  894. }
  895. /*!
  896. Gets the strength of the colorize filter, 1.0 means full colorized while
  897. 0.0 equals to no filtering at all.
  898. \internal
  899. */
  900. qreal QPixmapColorizeFilter::strength() const
  901. {
  902. Q_D(const QPixmapColorizeFilter);
  903. return d->strength;
  904. }
  905. /*!
  906. Sets the strength of the colorize filter to \a strength.
  907. \internal
  908. */
  909. void QPixmapColorizeFilter::setStrength(qreal strength)
  910. {
  911. Q_D(QPixmapColorizeFilter);
  912. d->strength = qBound(qreal(0), strength, qreal(1));
  913. d->opaque = !qFuzzyIsNull(d->strength);
  914. d->alphaBlend = !qFuzzyIsNull(d->strength - 1);
  915. }
  916. /*!
  917. \internal
  918. */
  919. void QPixmapColorizeFilter::draw(QPainter *painter, const QPointF &dest, const QPixmap &src, const QRectF &srcRect) const
  920. {
  921. Q_D(const QPixmapColorizeFilter);
  922. if (src.isNull())
  923. return;
  924. QPixmapFilter *filter = painter->paintEngine() && painter->paintEngine()->isExtended() ?
  925. static_cast<QPaintEngineEx *>(painter->paintEngine())->pixmapFilter(type(), this) : 0;
  926. QPixmapColorizeFilter *colorizeFilter = static_cast<QPixmapColorizeFilter*>(filter);
  927. if (colorizeFilter) {
  928. colorizeFilter->setColor(d->color);
  929. colorizeFilter->setStrength(d->strength);
  930. colorizeFilter->draw(painter, dest, src, srcRect);
  931. return;
  932. }
  933. // falling back to raster implementation
  934. if (!d->opaque) {
  935. painter->drawPixmap(dest, src, srcRect);
  936. return;
  937. }
  938. QImage srcImage;
  939. QImage destImage;
  940. if (srcRect.isNull()) {
  941. srcImage = src.toImage();
  942. srcImage = srcImage.convertToFormat(srcImage.hasAlphaChannel() ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32);
  943. destImage = QImage(srcImage.size(), srcImage.format());
  944. } else {
  945. QRect rect = srcRect.toAlignedRect().intersected(src.rect());
  946. srcImage = src.copy(rect).toImage();
  947. srcImage = srcImage.convertToFormat(srcImage.hasAlphaChannel() ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32);
  948. destImage = QImage(rect.size(), srcImage.format());
  949. }
  950. // do colorizing
  951. QPainter destPainter(&destImage);
  952. grayscale(srcImage, destImage, srcImage.rect());
  953. destPainter.setCompositionMode(QPainter::CompositionMode_Screen);
  954. destPainter.fillRect(srcImage.rect(), d->color);
  955. destPainter.end();
  956. if (d->alphaBlend) {
  957. // alpha blending srcImage and destImage
  958. QImage buffer = srcImage;
  959. QPainter bufPainter(&buffer);
  960. bufPainter.setOpacity(d->strength);
  961. bufPainter.drawImage(0, 0, destImage);
  962. bufPainter.end();
  963. destImage = buffer;
  964. }
  965. if (srcImage.hasAlphaChannel())
  966. destImage.setAlphaChannel(srcImage.alphaChannel());
  967. painter->drawImage(dest, destImage);
  968. }
  969. class QPixmapDropShadowFilterPrivate : public QPixmapFilterPrivate
  970. {
  971. public:
  972. QPixmapDropShadowFilterPrivate()
  973. : offset(8, 8), color(63, 63, 63, 180), radius(1) {}
  974. QPointF offset;
  975. QColor color;
  976. qreal radius;
  977. };
  978. /*!
  979. \class QPixmapDropShadowFilter
  980. \since 4.5
  981. \ingroup painting
  982. \brief The QPixmapDropShadowFilter class is a convenience class
  983. for drawing pixmaps with drop shadows.
  984. The drop shadow is produced by taking a copy of the source pixmap
  985. and applying a color to the copy using a
  986. QPainter::CompositionMode_DestinationIn operation. This produces a
  987. homogeneously-colored pixmap which is then drawn using a
  988. QPixmapConvolutionFilter at an offset. The original pixmap is
  989. drawn on top.
  990. The QPixmapDropShadowFilter class provides some customization
  991. options to specify how the drop shadow should appear. The color of
  992. the drop shadow can be modified using the setColor() function, the
  993. drop shadow offset can be modified using the setOffset() function,
  994. and the blur radius of the drop shadow can be changed through the
  995. setBlurRadius() function.
  996. By default, the drop shadow is a dark gray shadow, blurred with a
  997. radius of 1 at an offset of 8 pixels towards the lower right.
  998. Example:
  999. \snippet code/src_gui_image_qpixmapfilter.cpp 2
  1000. \sa QPixmapColorizeFilter, QPixmapConvolutionFilter
  1001. \internal
  1002. */
  1003. /*!
  1004. Constructs drop shadow filter.
  1005. \internal
  1006. */
  1007. QPixmapDropShadowFilter::QPixmapDropShadowFilter(QObject *parent)
  1008. : QPixmapFilter(*new QPixmapDropShadowFilterPrivate, DropShadowFilter, parent)
  1009. {
  1010. }
  1011. /*!
  1012. Destroys drop shadow filter.
  1013. \internal
  1014. */
  1015. QPixmapDropShadowFilter::~QPixmapDropShadowFilter()
  1016. {
  1017. }
  1018. /*!
  1019. Returns the radius in pixels of the blur on the drop shadow.
  1020. A smaller radius results in a sharper shadow.
  1021. \sa color(), offset()
  1022. \internal
  1023. */
  1024. qreal QPixmapDropShadowFilter::blurRadius() const
  1025. {
  1026. Q_D(const QPixmapDropShadowFilter);
  1027. return d->radius;
  1028. }
  1029. /*!
  1030. Sets the radius in pixels of the blur on the drop shadow to the \a radius specified.
  1031. Using a smaller radius results in a sharper shadow.
  1032. \sa setColor(), setOffset()
  1033. \internal
  1034. */
  1035. void QPixmapDropShadowFilter::setBlurRadius(qreal radius)
  1036. {
  1037. Q_D(QPixmapDropShadowFilter);
  1038. d->radius = radius;
  1039. }
  1040. /*!
  1041. Returns the color of the drop shadow.
  1042. \sa blurRadius(), offset()
  1043. \internal
  1044. */
  1045. QColor QPixmapDropShadowFilter::color() const
  1046. {
  1047. Q_D(const QPixmapDropShadowFilter);
  1048. return d->color;
  1049. }
  1050. /*!
  1051. Sets the color of the drop shadow to the \a color specified.
  1052. \sa setBlurRadius(), setOffset()
  1053. \internal
  1054. */
  1055. void QPixmapDropShadowFilter::setColor(const QColor &color)
  1056. {
  1057. Q_D(QPixmapDropShadowFilter);
  1058. d->color = color;
  1059. }
  1060. /*!
  1061. Returns the shadow offset in pixels.
  1062. \sa blurRadius(), color()
  1063. \internal
  1064. */
  1065. QPointF QPixmapDropShadowFilter::offset() const
  1066. {
  1067. Q_D(const QPixmapDropShadowFilter);
  1068. return d->offset;
  1069. }
  1070. /*!
  1071. Sets the shadow offset in pixels to the \a offset specified.
  1072. \sa setBlurRadius(), setColor()
  1073. \internal
  1074. */
  1075. void QPixmapDropShadowFilter::setOffset(const QPointF &offset)
  1076. {
  1077. Q_D(QPixmapDropShadowFilter);
  1078. d->offset = offset;
  1079. }
  1080. /*!
  1081. \fn void QPixmapDropShadowFilter::setOffset(qreal dx, qreal dy)
  1082. \overload
  1083. Sets the shadow offset in pixels to be the displacement specified by the
  1084. horizontal \a dx and vertical \a dy coordinates.
  1085. \sa setBlurRadius(), setColor()
  1086. \internal
  1087. */
  1088. /*!
  1089. \internal
  1090. */
  1091. QRectF QPixmapDropShadowFilter::boundingRectFor(const QRectF &rect) const
  1092. {
  1093. Q_D(const QPixmapDropShadowFilter);
  1094. return rect.united(rect.translated(d->offset).adjusted(-d->radius, -d->radius, d->radius, d->radius));
  1095. }
  1096. /*!
  1097. \internal
  1098. */
  1099. void QPixmapDropShadowFilter::draw(QPainter *p,
  1100. const QPointF &pos,
  1101. const QPixmap &px,
  1102. const QRectF &src) const
  1103. {
  1104. Q_D(const QPixmapDropShadowFilter);
  1105. if (px.isNull())
  1106. return;
  1107. QPixmapFilter *filter = p->paintEngine() && p->paintEngine()->isExtended() ?
  1108. static_cast<QPaintEngineEx *>(p->paintEngine())->pixmapFilter(type(), this) : 0;
  1109. QPixmapDropShadowFilter *dropShadowFilter = static_cast<QPixmapDropShadowFilter*>(filter);
  1110. if (dropShadowFilter) {
  1111. dropShadowFilter->setColor(d->color);
  1112. dropShadowFilter->setBlurRadius(d->radius);
  1113. dropShadowFilter->setOffset(d->offset);
  1114. dropShadowFilter->draw(p, pos, px, src);
  1115. return;
  1116. }
  1117. QImage tmp(px.size(), QImage::Format_ARGB32_Premultiplied);
  1118. tmp.fill(0);
  1119. QPainter tmpPainter(&tmp);
  1120. tmpPainter.setCompositionMode(QPainter::CompositionMode_Source);
  1121. tmpPainter.drawPixmap(d->offset, px);
  1122. tmpPainter.end();
  1123. // blur the alpha channel
  1124. QImage blurred(tmp.size(), QImage::Format_ARGB32_Premultiplied);
  1125. blurred.fill(0);
  1126. QPainter blurPainter(&blurred);
  1127. qt_blurImage(&blurPainter, tmp, d->radius, false, true);
  1128. blurPainter.end();
  1129. tmp = blurred;
  1130. // blacken the image...
  1131. tmpPainter.begin(&tmp);
  1132. tmpPainter.setCompositionMode(QPainter::CompositionMode_SourceIn);
  1133. tmpPainter.fillRect(tmp.rect(), d->color);
  1134. tmpPainter.end();
  1135. // draw the blurred drop shadow...
  1136. p->drawImage(pos, tmp);
  1137. // Draw the actual pixmap...
  1138. p->drawPixmap(pos, px, src);
  1139. }
  1140. QT_END_NAMESPACE
  1141. #endif //QT_NO_GRAPHICSEFFECT