• Skip to content
  • Skip to link menu
KDE 4.7 API Reference
  • KDE API Reference
  • kdelibs
  • KDE Home
  • Contact Us
 

Plasma

paintutils.cpp
Go to the documentation of this file.
00001 /*
00002  *   Copyright 2005 by Aaron Seigo <aseigo@kde.org>
00003  *   Copyright 2008 by Andrew Lake <jamboarder@yahoo.com>
00004  *
00005  *   This program is free software; you can redistribute it and/or modify
00006  *   it under the terms of the GNU Library General Public License as
00007  *   published by the Free Software Foundation; either version 2, or
00008  *   (at your option) any later version.
00009  *
00010  *   This program is distributed in the hope that it will be useful,
00011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  *   GNU General Public License for more details
00014  *
00015  *   You should have received a copy of the GNU Library General Public
00016  *   License along with this program; if not, write to the
00017  *   Free Software Foundation, Inc.,
00018  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00019  */
00020 
00021 #include <paintutils.h>
00022 
00023 #include <QImage>
00024 #include <QPainter>
00025 #include <QPaintEngine>
00026 #include <QPixmap>
00027 
00028 #include "private/effects/blur.cpp"
00029 #include "private/effects/halopainter_p.h"
00030 #include "svg.h"
00031 
00032 namespace Plasma
00033 {
00034 
00035 namespace PaintUtils
00036 {
00037 
00038 void shadowBlur(QImage &image, int radius, const QColor &color)
00039 {
00040     if (radius < 1) {
00041         return;
00042     }
00043     if (image.isNull()) {
00044         return;
00045     }
00046 
00047     expblur<16, 7>(image, radius);
00048 
00049     QPainter p(&image);
00050     p.setCompositionMode(QPainter::CompositionMode_SourceIn);
00051     p.fillRect(image.rect(), color);
00052     p.end();
00053 }
00054 
00055 //TODO: we should have shadowText methods that paint the results directly into a QPainter passed in
00056 QPixmap shadowText(QString text, QColor textColor, QColor shadowColor, QPoint offset, int radius)
00057 {
00058     return shadowText(text, qApp->font(), textColor, shadowColor, offset, radius);
00059 }
00060 
00061 QPixmap shadowText(QString text, const QFont &font, QColor textColor, QColor shadowColor, QPoint offset, int radius)
00062 {
00063     //don't try to paint stuff on a future null pixmap because the text is empty
00064     if (text.isEmpty()) {
00065         return QPixmap();
00066     }
00067 
00068     // Draw text
00069     QFontMetrics fm(font);
00070     QRect textRect = fm.boundingRect(text);
00071     QPixmap textPixmap(textRect.width(), fm.height());
00072     textPixmap.fill(Qt::transparent);
00073     QPainter p(&textPixmap);
00074     p.setPen(textColor);
00075     p.setFont(font);
00076     // FIXME: the center alignment here is odd: the rect should be the size needed by
00077     //        the text, but for some fonts and configurations this is off by a pixel or so
00078     //        and "centering" the text painting 'fixes' that. Need to research why
00079     //        this is the case and determine if we should be painting it differently here,
00080     //        doing soething different with the boundingRect call or if it's a problem
00081     //        in Qt itself
00082     p.drawText(textPixmap.rect(), Qt::AlignCenter, text);
00083     p.end();
00084 
00085     //Draw blurred shadow
00086     QImage img(textRect.size() + QSize(radius * 2, radius * 2), QImage::Format_ARGB32_Premultiplied);
00087     img.fill(0);
00088     p.begin(&img);
00089     p.drawImage(QPoint(radius, radius), textPixmap.toImage());
00090     p.end();
00091     shadowBlur(img, radius, shadowColor);
00092 
00093     //Compose text and shadow
00094     int addSizeX = qMax(0, qAbs(offset.x()) - radius);
00095     int addSizeY = qMax(0, qAbs(offset.y()) - radius);
00096 
00097     QPixmap finalPixmap(img.size() + QSize(addSizeX, addSizeY));
00098     finalPixmap.fill(Qt::transparent);
00099     p.begin(&finalPixmap);
00100     p.drawImage(qMax(0, offset.x()), qMax(0, offset.y()), img);
00101     p.drawPixmap(radius + qMax(0, -offset.x()), radius + qMax(0, -offset.y()), textPixmap);
00102     p.end();
00103 
00104     return finalPixmap;
00105 }
00106 
00107 QPixmap texturedText(const QString &text, const QFont &font, Plasma::Svg *texture)
00108 {
00109     QFontMetrics fm(font);
00110     //the text will be moved a bit from contentsRect
00111     QRect contentsRect = fm.boundingRect(text).adjusted(0, 0, 2, 2);
00112     contentsRect.moveTo(0,0);
00113 
00114     QPixmap pixmap(contentsRect.size());
00115     pixmap.fill(Qt::transparent);
00116 
00117     QPainter buffPainter(&pixmap);
00118     buffPainter.setPen(Qt::black);
00119 
00120     buffPainter.setFont(font);
00121     buffPainter.drawText(contentsRect, Qt::AlignCenter, text);
00122     buffPainter.setCompositionMode(QPainter::CompositionMode_SourceIn);
00123     texture->paint(&buffPainter, contentsRect, "foreground");
00124     buffPainter.end();
00125 
00126     //do the shadow
00127     QImage image(pixmap.size() + QSize(2, 2), QImage::Format_ARGB32_Premultiplied);
00128     image.fill(Qt::transparent);
00129     buffPainter.begin(&image);
00130     buffPainter.setFont(font);
00131     buffPainter.drawText(contentsRect.translated(1, 1), Qt::AlignCenter, text);
00132     buffPainter.setCompositionMode(QPainter::CompositionMode_SourceIn);
00133     texture->paint(&buffPainter, contentsRect.adjusted(-1, -1, 1, 1), "shadow");
00134     buffPainter.end();
00135 
00136     expblur<16, 7>(image, 1);
00137     //hole in the shadow
00138     buffPainter.begin(&image);
00139     buffPainter.setCompositionMode(QPainter::CompositionMode_DestinationOut);
00140     buffPainter.setFont(font);
00141     buffPainter.drawText(contentsRect.translated(1, 1), Qt::AlignCenter, text);
00142     buffPainter.end();
00143 
00144     QPixmap ret(image.size());
00145     ret.fill(Qt::transparent);
00146     buffPainter.begin(&ret);
00147     buffPainter.setCompositionMode(QPainter::CompositionMode_SourceOver);
00148     buffPainter.drawImage(QPoint(0,0), image);
00149     buffPainter.drawPixmap(QPoint(1,1), pixmap);
00150     return ret;
00151 }
00152 
00153 void drawHalo(QPainter *painter, const QRectF &rect)
00154 {
00155     HaloPainter::instance()->drawHalo(painter, rect.toRect());
00156 }
00157 
00158 QPainterPath roundedRectangle(const QRectF &rect, qreal radius)
00159 {
00160     QPainterPath path(QPointF(rect.left(), rect.top() + radius));
00161     path.quadTo(rect.left(), rect.top(), rect.left() + radius, rect.top());         // Top left corner
00162     path.lineTo(rect.right() - radius, rect.top());                                 // Top side
00163     path.quadTo(rect.right(), rect.top(), rect.right(), rect.top() + radius);       // Top right corner
00164     path.lineTo(rect.right(), rect.bottom() - radius);                              // Right side
00165     path.quadTo(rect.right(), rect.bottom(), rect.right() - radius, rect.bottom()); // Bottom right corner
00166     path.lineTo(rect.left() + radius, rect.bottom());                               // Bottom side
00167     path.quadTo(rect.left(), rect.bottom(), rect.left(), rect.bottom() - radius);   // Bottom left corner
00168     path.closeSubpath();
00169 
00170     return path;
00171 }
00172 
00173 void centerPixmaps(QPixmap &from, QPixmap &to)
00174 {
00175     if (from.size() == to.size() && from.hasAlphaChannel() && to.hasAlphaChannel()) {
00176         return;
00177     }
00178 
00179     QRect fromRect(from.rect());
00180     QRect toRect(to.rect());
00181  
00182     QRect actualRect = QRect(QPoint(0,0), fromRect.size().expandedTo(toRect.size()));
00183     fromRect.moveCenter(actualRect.center());
00184     toRect.moveCenter(actualRect.center());
00185 
00186     if (from.size() != actualRect.size() || !from.hasAlphaChannel()) {
00187         QPixmap result(actualRect.size());
00188         result.fill(Qt::transparent);
00189         QPainter p(&result);
00190         p.setCompositionMode(QPainter::CompositionMode_Source);
00191         p.drawPixmap(fromRect.topLeft(), from);
00192         p.end();
00193         from = result;
00194     }
00195 
00196     if (to.size() != actualRect.size() || !to.hasAlphaChannel()) {
00197         QPixmap result(actualRect.size());
00198         result.fill(Qt::transparent);
00199         QPainter p(&result);
00200         p.setCompositionMode(QPainter::CompositionMode_Source);
00201         p.drawPixmap(toRect.topLeft(), to);
00202         p.end();
00203         to = result;
00204     }
00205 }
00206 
00207 QPixmap transition(const QPixmap &from, const QPixmap &to, qreal amount)
00208 {
00209     if (from.isNull() && to.isNull()) {
00210         return from;
00211     }
00212 
00213     if (qFuzzyCompare(amount + 1, qreal(1.0))) {
00214         return from;
00215     }
00216 
00217     QRect startRect(from.rect());
00218     QRect targetRect(to.rect());
00219     QSize pixmapSize = startRect.size().expandedTo(targetRect.size());
00220     QRect toRect = QRect(QPoint(0,0), pixmapSize);
00221     targetRect.moveCenter(toRect.center());
00222     startRect.moveCenter(toRect.center());
00223 
00224     //paint to in the center of from
00225     QColor color;
00226     color.setAlphaF(amount);
00227 
00228     // If the native paint engine supports Porter/Duff compositing and CompositionMode_Plus
00229     QPaintEngine *paintEngine = from.paintEngine();
00230     if (paintEngine && 
00231         paintEngine->hasFeature(QPaintEngine::PorterDuff) &&
00232         paintEngine->hasFeature(QPaintEngine::BlendModes)) {
00233         QPixmap startPixmap(pixmapSize);
00234         startPixmap.fill(Qt::transparent);
00235 
00236         QPixmap targetPixmap(pixmapSize);
00237         targetPixmap.fill(Qt::transparent);
00238 
00239         QPainter p;
00240         p.begin(&targetPixmap);
00241         p.drawPixmap(targetRect, to);
00242         p.setCompositionMode(QPainter::CompositionMode_DestinationIn);
00243         p.fillRect(targetRect, color);
00244         p.end();
00245 
00246         p.begin(&startPixmap);
00247         p.drawPixmap(startRect, from);
00248         p.setCompositionMode(QPainter::CompositionMode_DestinationOut);
00249         p.fillRect(startRect, color);
00250         p.setCompositionMode(QPainter::CompositionMode_Plus);
00251         p.drawPixmap(targetRect, targetPixmap);
00252         p.end();
00253 
00254         return startPixmap;
00255     }
00256 #if defined(Q_WS_X11) && defined(HAVE_XRENDER)
00257     // We have Xrender support
00258     else if (paintEngine && paintEngine->hasFeature(QPaintEngine::PorterDuff)) {
00259         // QX11PaintEngine doesn't implement CompositionMode_Plus in Qt 4.3,
00260         // which we need to be able to do a transition from one pixmap to
00261         // another.
00262         //
00263         // In order to avoid the overhead of converting the pixmaps to images
00264         // and doing the operation entirely in software, this function has a
00265         // specialized path for X11 that uses Xrender directly to do the
00266         // transition. This operation can be fully accelerated in HW.
00267         //
00268         // This specialization can be removed when QX11PaintEngine supports
00269         // CompositionMode_Plus.
00270         QPixmap source(targetPixmap), destination(startPixmap);
00271 
00272         source.detach();
00273         destination.detach();
00274 
00275         Display *dpy = QX11Info::display();
00276 
00277         XRenderPictFormat *format = XRenderFindStandardFormat(dpy, PictStandardA8);
00278         XRenderPictureAttributes pa;
00279         pa.repeat = 1; // RepeatNormal
00280 
00281         // Create a 1x1 8 bit repeating alpha picture
00282         Pixmap pixmap = XCreatePixmap(dpy, destination.handle(), 1, 1, 8);
00283         Picture alpha = XRenderCreatePicture(dpy, pixmap, format, CPRepeat, &pa);
00284         XFreePixmap(dpy, pixmap);
00285 
00286         // Fill the alpha picture with the opacity value
00287         XRenderColor xcolor;
00288         xcolor.alpha = quint16(0xffff * amount);
00289         XRenderFillRectangle(dpy, PictOpSrc, alpha, &xcolor, 0, 0, 1, 1);
00290 
00291         // Reduce the alpha of the destination with 1 - opacity
00292         XRenderComposite(dpy, PictOpOutReverse, alpha, None, destination.x11PictureHandle(),
00293                          0, 0, 0, 0, 0, 0, destination.width(), destination.height());
00294 
00295         // Add source * opacity to the destination
00296         XRenderComposite(dpy, PictOpAdd, source.x11PictureHandle(), alpha,
00297                          destination.x11PictureHandle(),
00298                          toRect.x(), toRect.y(), 0, 0, 0, 0, destination.width(), destination.height());
00299 
00300         XRenderFreePicture(dpy, alpha);
00301         return destination;
00302     }
00303 #endif
00304     else {
00305         // Fall back to using QRasterPaintEngine to do the transition.
00306         QImage under(pixmapSize, QImage::Format_ARGB32_Premultiplied);
00307         under.fill(Qt::transparent);
00308         QImage over(pixmapSize, QImage::Format_ARGB32_Premultiplied);
00309         over.fill(Qt::transparent);
00310 
00311         QPainter p;
00312         p.begin(&over);
00313         p.drawPixmap(targetRect, to);
00314         p.setCompositionMode(QPainter::CompositionMode_DestinationIn);
00315         p.fillRect(over.rect(), color);
00316         p.end();
00317 
00318         p.begin(&under);
00319         p.drawPixmap(startRect, from);
00320         p.setCompositionMode(QPainter::CompositionMode_DestinationOut);
00321         p.fillRect(startRect, color);
00322         p.setCompositionMode(QPainter::CompositionMode_Plus);
00323         p.drawImage(toRect.topLeft(), over);
00324         p.end();
00325 
00326         return QPixmap::fromImage(under);
00327     }
00328 }
00329 
00330 } // PaintUtils namespace
00331 
00332 } // Plasma namespace
00333 

Plasma

Skip menu "Plasma"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.7.5
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal