• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.8.3 API Reference
  • 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     buffPainter.end();
00151     return ret;
00152 }
00153 
00154 void drawHalo(QPainter *painter, const QRectF &rect)
00155 {
00156     HaloPainter::instance()->drawHalo(painter, rect.toRect());
00157 }
00158 
00159 QPainterPath roundedRectangle(const QRectF &rect, qreal radius)
00160 {
00161     QPainterPath path(QPointF(rect.left(), rect.top() + radius));
00162     path.quadTo(rect.left(), rect.top(), rect.left() + radius, rect.top());         // Top left corner
00163     path.lineTo(rect.right() - radius, rect.top());                                 // Top side
00164     path.quadTo(rect.right(), rect.top(), rect.right(), rect.top() + radius);       // Top right corner
00165     path.lineTo(rect.right(), rect.bottom() - radius);                              // Right side
00166     path.quadTo(rect.right(), rect.bottom(), rect.right() - radius, rect.bottom()); // Bottom right corner
00167     path.lineTo(rect.left() + radius, rect.bottom());                               // Bottom side
00168     path.quadTo(rect.left(), rect.bottom(), rect.left(), rect.bottom() - radius);   // Bottom left corner
00169     path.closeSubpath();
00170 
00171     return path;
00172 }
00173 
00174 void centerPixmaps(QPixmap &from, QPixmap &to)
00175 {
00176     if (from.size() == to.size() && from.hasAlphaChannel() && to.hasAlphaChannel()) {
00177         return;
00178     }
00179 
00180     QRect fromRect(from.rect());
00181     QRect toRect(to.rect());
00182  
00183     QRect actualRect = QRect(QPoint(0,0), fromRect.size().expandedTo(toRect.size()));
00184     fromRect.moveCenter(actualRect.center());
00185     toRect.moveCenter(actualRect.center());
00186 
00187     if (from.size() != actualRect.size() || !from.hasAlphaChannel()) {
00188         QPixmap result(actualRect.size());
00189         result.fill(Qt::transparent);
00190         QPainter p(&result);
00191         p.setCompositionMode(QPainter::CompositionMode_Source);
00192         p.drawPixmap(fromRect.topLeft(), from);
00193         p.end();
00194         from = result;
00195     }
00196 
00197     if (to.size() != actualRect.size() || !to.hasAlphaChannel()) {
00198         QPixmap result(actualRect.size());
00199         result.fill(Qt::transparent);
00200         QPainter p(&result);
00201         p.setCompositionMode(QPainter::CompositionMode_Source);
00202         p.drawPixmap(toRect.topLeft(), to);
00203         p.end();
00204         to = result;
00205     }
00206 }
00207 
00208 QPixmap transition(const QPixmap &from, const QPixmap &to, qreal amount)
00209 {
00210     if (from.isNull() && to.isNull()) {
00211         return from;
00212     }
00213 
00214     if (qFuzzyCompare(amount + 1, qreal(1.0))) {
00215         return from;
00216     }
00217 
00218     QRect startRect(from.rect());
00219     QRect targetRect(to.rect());
00220     QSize pixmapSize = startRect.size().expandedTo(targetRect.size());
00221     QRect toRect = QRect(QPoint(0,0), pixmapSize);
00222     targetRect.moveCenter(toRect.center());
00223     startRect.moveCenter(toRect.center());
00224 
00225     //paint to in the center of from
00226     QColor color;
00227     color.setAlphaF(amount);
00228 
00229     // If the native paint engine supports Porter/Duff compositing and CompositionMode_Plus
00230     QPaintEngine *paintEngine = from.paintEngine();
00231     if (paintEngine && 
00232         paintEngine->hasFeature(QPaintEngine::PorterDuff) &&
00233         paintEngine->hasFeature(QPaintEngine::BlendModes)) {
00234         QPixmap startPixmap(pixmapSize);
00235         startPixmap.fill(Qt::transparent);
00236 
00237         QPixmap targetPixmap(pixmapSize);
00238         targetPixmap.fill(Qt::transparent);
00239 
00240         QPainter p;
00241         p.begin(&targetPixmap);
00242         p.drawPixmap(targetRect, to);
00243         p.setCompositionMode(QPainter::CompositionMode_DestinationIn);
00244         p.fillRect(targetRect, color);
00245         p.end();
00246 
00247         p.begin(&startPixmap);
00248         p.drawPixmap(startRect, from);
00249         p.setCompositionMode(QPainter::CompositionMode_DestinationOut);
00250         p.fillRect(startRect, color);
00251         p.setCompositionMode(QPainter::CompositionMode_Plus);
00252         p.drawPixmap(targetRect, targetPixmap);
00253         p.end();
00254 
00255         return startPixmap;
00256     }
00257 #if defined(Q_WS_X11) && defined(HAVE_XRENDER)
00258     // We have Xrender support
00259     else if (paintEngine && paintEngine->hasFeature(QPaintEngine::PorterDuff)) {
00260         // QX11PaintEngine doesn't implement CompositionMode_Plus in Qt 4.3,
00261         // which we need to be able to do a transition from one pixmap to
00262         // another.
00263         //
00264         // In order to avoid the overhead of converting the pixmaps to images
00265         // and doing the operation entirely in software, this function has a
00266         // specialized path for X11 that uses Xrender directly to do the
00267         // transition. This operation can be fully accelerated in HW.
00268         //
00269         // This specialization can be removed when QX11PaintEngine supports
00270         // CompositionMode_Plus.
00271         QPixmap source(targetPixmap), destination(startPixmap);
00272 
00273         source.detach();
00274         destination.detach();
00275 
00276         Display *dpy = QX11Info::display();
00277 
00278         XRenderPictFormat *format = XRenderFindStandardFormat(dpy, PictStandardA8);
00279         XRenderPictureAttributes pa;
00280         pa.repeat = 1; // RepeatNormal
00281 
00282         // Create a 1x1 8 bit repeating alpha picture
00283         Pixmap pixmap = XCreatePixmap(dpy, destination.handle(), 1, 1, 8);
00284         Picture alpha = XRenderCreatePicture(dpy, pixmap, format, CPRepeat, &pa);
00285         XFreePixmap(dpy, pixmap);
00286 
00287         // Fill the alpha picture with the opacity value
00288         XRenderColor xcolor;
00289         xcolor.alpha = quint16(0xffff * amount);
00290         XRenderFillRectangle(dpy, PictOpSrc, alpha, &xcolor, 0, 0, 1, 1);
00291 
00292         // Reduce the alpha of the destination with 1 - opacity
00293         XRenderComposite(dpy, PictOpOutReverse, alpha, None, destination.x11PictureHandle(),
00294                          0, 0, 0, 0, 0, 0, destination.width(), destination.height());
00295 
00296         // Add source * opacity to the destination
00297         XRenderComposite(dpy, PictOpAdd, source.x11PictureHandle(), alpha,
00298                          destination.x11PictureHandle(),
00299                          toRect.x(), toRect.y(), 0, 0, 0, 0, destination.width(), destination.height());
00300 
00301         XRenderFreePicture(dpy, alpha);
00302         return destination;
00303     }
00304 #endif
00305     else {
00306         // Fall back to using QRasterPaintEngine to do the transition.
00307         QImage under(pixmapSize, QImage::Format_ARGB32_Premultiplied);
00308         under.fill(Qt::transparent);
00309         QImage over(pixmapSize, QImage::Format_ARGB32_Premultiplied);
00310         over.fill(Qt::transparent);
00311 
00312         QPainter p;
00313         p.begin(&over);
00314         p.drawPixmap(targetRect, to);
00315         p.setCompositionMode(QPainter::CompositionMode_DestinationIn);
00316         p.fillRect(over.rect(), color);
00317         p.end();
00318 
00319         p.begin(&under);
00320         p.drawPixmap(startRect, from);
00321         p.setCompositionMode(QPainter::CompositionMode_DestinationOut);
00322         p.fillRect(startRect, color);
00323         p.setCompositionMode(QPainter::CompositionMode_Plus);
00324         p.drawImage(toRect.topLeft(), over);
00325         p.end();
00326 
00327         return QPixmap::fromImage(under);
00328     }
00329 }
00330 
00331 } // PaintUtils namespace
00332 
00333 } // Plasma namespace
00334 
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Wed May 2 2012 17:36:13 by doxygen 1.8.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

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-4.8.3 API Reference

Skip menu "kdelibs-4.8.3 API Reference"
  • 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
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal