| /**************************************************************************** |
| ** |
| ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). |
| ** All rights reserved. |
| ** Contact: Nokia Corporation (qt-info@nokia.com) |
| ** |
| ** This file is part of the QtOpenVG module of the Qt Toolkit. |
| ** |
| ** $QT_BEGIN_LICENSE:LGPL$ |
| ** GNU Lesser General Public License Usage |
| ** This file may be used under the terms of the GNU Lesser General Public |
| ** License version 2.1 as published by the Free Software Foundation and |
| ** appearing in the file LICENSE.LGPL included in the packaging of this |
| ** file. Please review the following information to ensure the GNU Lesser |
| ** General Public License version 2.1 requirements will be met: |
| ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
| ** |
| ** In addition, as a special exception, Nokia gives you certain additional |
| ** rights. These rights are described in the Nokia Qt LGPL Exception |
| ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
| ** |
| ** GNU General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU General |
| ** Public License version 3.0 as published by the Free Software Foundation |
| ** and appearing in the file LICENSE.GPL included in the packaging of this |
| ** file. Please review the following information to ensure the GNU General |
| ** Public License version 3.0 requirements will be met: |
| ** http://www.gnu.org/copyleft/gpl.html. |
| ** |
| ** Other Usage |
| ** Alternatively, this file may be used in accordance with the terms and |
| ** conditions contained in a signed written agreement between you and Nokia. |
| ** |
| ** |
| ** |
| ** |
| ** |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| #include "qpixmapfilter_vg_p.h" |
| #include "qvgimagepool_p.h" |
| #include <QtCore/qvarlengtharray.h> |
| #include <QtGui/qpainter.h> |
| |
| QT_BEGIN_NAMESPACE |
| |
| #if !defined(QT_SHIVAVG) |
| |
| QVGPixmapConvolutionFilter::QVGPixmapConvolutionFilter() |
| : QPixmapConvolutionFilter() |
| { |
| } |
| |
| QVGPixmapConvolutionFilter::~QVGPixmapConvolutionFilter() |
| { |
| } |
| |
| extern void qt_vg_drawVGImage |
| (QPainter *painter, const QPointF& pos, VGImage vgImg); |
| extern void qt_vg_drawVGImageStencil |
| (QPainter *painter, const QPointF& pos, VGImage vgImg, const QBrush& brush); |
| |
| void QVGPixmapConvolutionFilter::draw |
| (QPainter *painter, const QPointF &dest, |
| const QPixmap &src, const QRectF &srcRect) const |
| { |
| if (src.isNull()) |
| return; |
| |
| if (src.pixmapData()->classId() != QPixmapData::OpenVGClass) { |
| // The pixmap data is not an instance of QVGPixmapData, so fall |
| // back to the default convolution filter implementation. |
| QPixmapConvolutionFilter::draw(painter, dest, src, srcRect); |
| return; |
| } |
| |
| QVGPixmapData *pd = static_cast<QVGPixmapData *>(src.pixmapData()); |
| |
| VGImage srcImage = pd->toVGImage(); |
| if (srcImage == VG_INVALID_HANDLE) |
| return; |
| |
| QSize size = pd->size(); |
| VGImage dstImage = QVGImagePool::instance()->createTemporaryImage |
| (VG_sARGB_8888_PRE, size.width(), size.height(), |
| VG_IMAGE_QUALITY_FASTER, pd); |
| if (dstImage == VG_INVALID_HANDLE) |
| return; |
| |
| int kernelWidth = rows(); |
| int kernelHeight = columns(); |
| const qreal *kern = convolutionKernel(); |
| QVarLengthArray<VGshort> kernel; |
| for (int i = 0; i < kernelWidth; ++i) { |
| for (int j = 0; j < kernelHeight; ++j) { |
| kernel.append((VGshort)(kern[j * kernelWidth + i] * 1024.0f)); |
| } |
| } |
| |
| VGfloat values[4]; |
| values[0] = 0.0f; |
| values[1] = 0.0f; |
| values[2] = 0.0f; |
| values[3] = 0.0f; |
| vgSetfv(VG_TILE_FILL_COLOR, 4, values); |
| |
| vgConvolve(dstImage, srcImage, |
| kernelWidth, kernelHeight, 0, 0, |
| kernel.constData(), 1.0f / 1024.0f, 0.0f, |
| VG_TILE_FILL); |
| |
| VGImage child = VG_INVALID_HANDLE; |
| |
| if (srcRect.isNull() || |
| (srcRect.topLeft().isNull() && srcRect.size() == size)) { |
| child = dstImage; |
| } else { |
| QRect src = srcRect.toRect(); |
| child = vgChildImage(dstImage, src.x(), src.y(), src.width(), src.height()); |
| } |
| |
| qt_vg_drawVGImage(painter, dest, child); |
| |
| if(child != dstImage) |
| vgDestroyImage(child); |
| QVGImagePool::instance()->releaseImage(0, dstImage); |
| } |
| |
| QVGPixmapColorizeFilter::QVGPixmapColorizeFilter() |
| : QPixmapColorizeFilter() |
| { |
| } |
| |
| QVGPixmapColorizeFilter::~QVGPixmapColorizeFilter() |
| { |
| } |
| |
| void QVGPixmapColorizeFilter::draw(QPainter *painter, const QPointF &dest, const QPixmap &src, const QRectF &srcRect) const |
| { |
| if (src.isNull()) |
| return; |
| |
| if (src.pixmapData()->classId() != QPixmapData::OpenVGClass) { |
| // The pixmap data is not an instance of QVGPixmapData, so fall |
| // back to the default colorize filter implementation. |
| QPixmapColorizeFilter::draw(painter, dest, src, srcRect); |
| return; |
| } |
| |
| QVGPixmapData *pd = static_cast<QVGPixmapData *>(src.pixmapData()); |
| |
| VGImage srcImage = pd->toVGImage(); |
| if (srcImage == VG_INVALID_HANDLE) |
| return; |
| |
| QSize size = pd->size(); |
| VGImage dstImage = QVGImagePool::instance()->createTemporaryImage |
| (VG_sARGB_8888_PRE, size.width(), size.height(), |
| VG_IMAGE_QUALITY_FASTER, pd); |
| if (dstImage == VG_INVALID_HANDLE) |
| return; |
| |
| // Determine the weights for the matrix from the color and strength. |
| QColor c = color(); |
| VGfloat strength = this->strength(); |
| VGfloat weights[3]; |
| VGfloat invweights[3]; |
| VGfloat alpha = c.alphaF(); |
| weights[0] = c.redF() * alpha; |
| weights[1] = c.greenF() * alpha; |
| weights[2] = c.blueF() * alpha; |
| invweights[0] = (1.0f - weights[0]) * strength; |
| invweights[1] = (1.0f - weights[1]) * strength; |
| invweights[2] = (1.0f - weights[2]) * strength; |
| |
| // Grayscale weights. |
| static const VGfloat redGray = 11.0f / 32.0f; |
| static const VGfloat greenGray = 16.0f / 32.0f; |
| static const VGfloat blueGray = 1.0f - (redGray + greenGray); |
| |
| VGfloat matrix[5][4]; |
| matrix[0][0] = redGray * invweights[0] + (1.0f - strength); |
| matrix[0][1] = redGray * invweights[1]; |
| matrix[0][2] = redGray * invweights[2]; |
| matrix[0][3] = 0.0f; |
| matrix[1][0] = greenGray * invweights[0]; |
| matrix[1][1] = greenGray * invweights[1] + (1.0f - strength); |
| matrix[1][2] = greenGray * invweights[2]; |
| matrix[1][3] = 0.0f; |
| matrix[2][0] = blueGray * invweights[0]; |
| matrix[2][1] = blueGray * invweights[1]; |
| matrix[2][2] = blueGray * invweights[2] + (1.0f - strength); |
| matrix[2][3] = 0.0f; |
| matrix[3][0] = 0.0f; |
| matrix[3][1] = 0.0f; |
| matrix[3][2] = 0.0f; |
| matrix[3][3] = 1.0f; |
| matrix[4][0] = weights[0] * strength; |
| matrix[4][1] = weights[1] * strength; |
| matrix[4][2] = weights[2] * strength; |
| matrix[4][3] = 0.0f; |
| |
| vgColorMatrix(dstImage, srcImage, matrix[0]); |
| |
| VGImage child = VG_INVALID_HANDLE; |
| |
| if (srcRect.isNull() || |
| (srcRect.topLeft().isNull() && srcRect.size() == size)) { |
| child = dstImage; |
| } else { |
| QRect src = srcRect.toRect(); |
| child = vgChildImage(dstImage, src.x(), src.y(), src.width(), src.height()); |
| } |
| |
| qt_vg_drawVGImage(painter, dest, child); |
| |
| if(child != dstImage) |
| vgDestroyImage(child); |
| QVGImagePool::instance()->releaseImage(0, dstImage); |
| } |
| |
| QVGPixmapDropShadowFilter::QVGPixmapDropShadowFilter() |
| : QPixmapDropShadowFilter() |
| { |
| } |
| |
| QVGPixmapDropShadowFilter::~QVGPixmapDropShadowFilter() |
| { |
| } |
| |
| void QVGPixmapDropShadowFilter::draw(QPainter *painter, const QPointF &dest, const QPixmap &src, const QRectF &srcRect) const |
| { |
| if (src.isNull()) |
| return; |
| |
| if (src.pixmapData()->classId() != QPixmapData::OpenVGClass) { |
| // The pixmap data is not an instance of QVGPixmapData, so fall |
| // back to the default drop shadow filter implementation. |
| QPixmapDropShadowFilter::draw(painter, dest, src, srcRect); |
| return; |
| } |
| |
| QVGPixmapData *pd = static_cast<QVGPixmapData *>(src.pixmapData()); |
| |
| VGImage srcImage = pd->toVGImage(); |
| if (srcImage == VG_INVALID_HANDLE) |
| return; |
| |
| QSize size = pd->size(); |
| VGImage dstImage = QVGImagePool::instance()->createTemporaryImage |
| (VG_A_8, size.width(), size.height(), |
| VG_IMAGE_QUALITY_FASTER, pd); |
| if (dstImage == VG_INVALID_HANDLE) |
| return; |
| |
| // Clamp the radius range. We divide by 2 because the OpenVG blur |
| // is "too blurry" compared to the default raster implementation. |
| VGfloat maxRadius = VGfloat(vgGeti(VG_MAX_GAUSSIAN_STD_DEVIATION)); |
| VGfloat radiusF = VGfloat(blurRadius()) / 2.0f; |
| if (radiusF < 0.001f) |
| radiusF = 0.001f; |
| else if (radiusF > maxRadius) |
| radiusF = maxRadius; |
| |
| // Blur the blackened source image. |
| vgGaussianBlur(dstImage, srcImage, radiusF, radiusF, VG_TILE_PAD); |
| |
| VGImage child = VG_INVALID_HANDLE; |
| |
| QRect srect; |
| if (srcRect.isNull() || |
| (srcRect.topLeft().isNull() && srcRect.size() == size)) { |
| child = dstImage; |
| srect = QRect(0, 0, size.width(), size.height()); |
| } else { |
| srect = srcRect.toRect(); |
| child = vgChildImage(dstImage, srect.x(), srect.y(), srect.width(), srect.height()); |
| } |
| |
| qt_vg_drawVGImageStencil(painter, dest + offset(), child, color()); |
| |
| if(child != dstImage) |
| vgDestroyImage(child); |
| QVGImagePool::instance()->releaseImage(0, dstImage); |
| |
| // Now draw the actual pixmap over the top. |
| painter->drawPixmap(dest, src, srect); |
| } |
| |
| QVGPixmapBlurFilter::QVGPixmapBlurFilter(QObject *parent) |
| : QPixmapBlurFilter(parent) |
| { |
| } |
| |
| QVGPixmapBlurFilter::~QVGPixmapBlurFilter() |
| { |
| } |
| |
| void QVGPixmapBlurFilter::draw(QPainter *painter, const QPointF &dest, const QPixmap &src, const QRectF &srcRect) const |
| { |
| if (src.isNull()) |
| return; |
| |
| if (src.pixmapData()->classId() != QPixmapData::OpenVGClass) { |
| // The pixmap data is not an instance of QVGPixmapData, so fall |
| // back to the default blur filter implementation. |
| QPixmapBlurFilter::draw(painter, dest, src, srcRect); |
| return; |
| } |
| |
| QVGPixmapData *pd = static_cast<QVGPixmapData *>(src.pixmapData()); |
| |
| VGImage srcImage = pd->toVGImage(); |
| if (srcImage == VG_INVALID_HANDLE) |
| return; |
| |
| QSize size = pd->size(); |
| VGImage dstImage = QVGImagePool::instance()->createTemporaryImage |
| (VG_sARGB_8888_PRE, size.width(), size.height(), |
| VG_IMAGE_QUALITY_FASTER, pd); |
| if (dstImage == VG_INVALID_HANDLE) |
| return; |
| |
| // Clamp the radius range. We divide by 2 because the OpenVG blur |
| // is "too blurry" compared to the default raster implementation. |
| VGfloat maxRadius = VGfloat(vgGeti(VG_MAX_GAUSSIAN_STD_DEVIATION)); |
| VGfloat radiusF = VGfloat(radius()) / 2.0f; |
| if (radiusF < 0.001f) |
| radiusF = 0.001f; |
| else if (radiusF > maxRadius) |
| radiusF = maxRadius; |
| |
| vgGaussianBlur(dstImage, srcImage, radiusF, radiusF, VG_TILE_PAD); |
| |
| VGImage child = VG_INVALID_HANDLE; |
| |
| if (srcRect.isNull() || |
| (srcRect.topLeft().isNull() && srcRect.size() == size)) { |
| child = dstImage; |
| } else { |
| QRect src = srcRect.toRect(); |
| child = vgChildImage(dstImage, src.x(), src.y(), src.width(), src.height()); |
| } |
| |
| qt_vg_drawVGImage(painter, dest, child); |
| |
| if(child != dstImage) |
| vgDestroyImage(child); |
| QVGImagePool::instance()->releaseImage(0, dstImage); |
| } |
| |
| #endif |
| |
| QT_END_NAMESPACE |