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 00031 namespace Plasma 00032 { 00033 00034 namespace PaintUtils 00035 { 00036 00037 void shadowBlur(QImage &image, int radius, const QColor &color) 00038 { 00039 if (radius < 1) { 00040 return; 00041 } 00042 if (image.isNull()) { 00043 return; 00044 } 00045 00046 expblur<16, 7>(image, radius); 00047 00048 QPainter p(&image); 00049 p.setCompositionMode(QPainter::CompositionMode_SourceIn); 00050 p.fillRect(image.rect(), color); 00051 p.end(); 00052 } 00053 00054 //TODO: we should have shadowText methods that paint the results directly into a QPainter passed in 00055 QPixmap shadowText(QString text, QColor textColor, QColor shadowColor, QPoint offset, int radius) 00056 { 00057 return shadowText(text, qApp->font(), textColor, shadowColor, offset, radius); 00058 } 00059 00060 QPixmap shadowText(QString text, const QFont &font, QColor textColor, QColor shadowColor, QPoint offset, int radius) 00061 { 00062 //don't try to paint stuff on a future null pixmap because the text is empty 00063 if (text.isEmpty()) { 00064 return QPixmap(); 00065 } 00066 00067 // Draw text 00068 QFontMetrics fm(font); 00069 QRect textRect = fm.boundingRect(text); 00070 QPixmap textPixmap(textRect.width(), fm.height()); 00071 textPixmap.fill(Qt::transparent); 00072 QPainter p(&textPixmap); 00073 p.setPen(textColor); 00074 p.setFont(font); 00075 // FIXME: the center alignment here is odd: the rect should be the size needed by 00076 // the text, but for some fonts and configurations this is off by a pixel or so 00077 // and "centering" the text painting 'fixes' that. Need to research why 00078 // this is the case and determine if we should be painting it differently here, 00079 // doing soething different with the boundingRect call or if it's a problem 00080 // in Qt itself 00081 p.drawText(textPixmap.rect(), Qt::AlignCenter, text); 00082 p.end(); 00083 00084 //Draw blurred shadow 00085 QImage img(textRect.size() + QSize(radius * 2, radius * 2), QImage::Format_ARGB32_Premultiplied); 00086 img.fill(0); 00087 p.begin(&img); 00088 p.drawImage(QPoint(radius, radius), textPixmap.toImage()); 00089 p.end(); 00090 shadowBlur(img, radius, shadowColor); 00091 00092 //Compose text and shadow 00093 int addSizeX = qMax(0, qAbs(offset.x()) - radius); 00094 int addSizeY = qMax(0, qAbs(offset.y()) - radius); 00095 00096 QPixmap finalPixmap(img.size() + QSize(addSizeX, addSizeY)); 00097 finalPixmap.fill(Qt::transparent); 00098 p.begin(&finalPixmap); 00099 p.drawImage(qMax(0, offset.x()), qMax(0, offset.y()), img); 00100 p.drawPixmap(radius + qMax(0, -offset.x()), radius + qMax(0, -offset.y()), textPixmap); 00101 p.end(); 00102 00103 return finalPixmap; 00104 } 00105 00106 void drawHalo(QPainter *painter, const QRectF &rect) 00107 { 00108 HaloPainter::instance()->drawHalo(painter, rect.toRect()); 00109 } 00110 00111 QPainterPath roundedRectangle(const QRectF &rect, qreal radius) 00112 { 00113 QPainterPath path(QPointF(rect.left(), rect.top() + radius)); 00114 path.quadTo(rect.left(), rect.top(), rect.left() + radius, rect.top()); // Top left corner 00115 path.lineTo(rect.right() - radius, rect.top()); // Top side 00116 path.quadTo(rect.right(), rect.top(), rect.right(), rect.top() + radius); // Top right corner 00117 path.lineTo(rect.right(), rect.bottom() - radius); // Right side 00118 path.quadTo(rect.right(), rect.bottom(), rect.right() - radius, rect.bottom()); // Bottom right corner 00119 path.lineTo(rect.left() + radius, rect.bottom()); // Bottom side 00120 path.quadTo(rect.left(), rect.bottom(), rect.left(), rect.bottom() - radius); // Bottom left corner 00121 path.closeSubpath(); 00122 00123 return path; 00124 } 00125 00126 void centerPixmaps(QPixmap &from, QPixmap &to) 00127 { 00128 if (from.size() == to.size() && from.hasAlphaChannel() && to.hasAlphaChannel()) { 00129 return; 00130 } 00131 00132 QRect fromRect(from.rect()); 00133 QRect toRect(to.rect()); 00134 00135 QRect actualRect = QRect(QPoint(0,0), fromRect.size().expandedTo(toRect.size())); 00136 fromRect.moveCenter(actualRect.center()); 00137 toRect.moveCenter(actualRect.center()); 00138 00139 if (from.size() != actualRect.size() || !from.hasAlphaChannel()) { 00140 QPixmap result(actualRect.size()); 00141 result.fill(Qt::transparent); 00142 QPainter p(&result); 00143 p.setCompositionMode(QPainter::CompositionMode_Source); 00144 p.drawPixmap(fromRect.topLeft(), from); 00145 p.end(); 00146 from = result; 00147 } 00148 00149 if (to.size() != actualRect.size() || !to.hasAlphaChannel()) { 00150 QPixmap result(actualRect.size()); 00151 result.fill(Qt::transparent); 00152 QPainter p(&result); 00153 p.setCompositionMode(QPainter::CompositionMode_Source); 00154 p.drawPixmap(toRect.topLeft(), to); 00155 p.end(); 00156 to = result; 00157 } 00158 } 00159 00160 QPixmap transition(const QPixmap &from, const QPixmap &to, qreal amount) 00161 { 00162 if (from.isNull() && to.isNull()) { 00163 return from; 00164 } 00165 00166 if (qFuzzyCompare(amount + 1, qreal(1.0))) { 00167 return from; 00168 } 00169 00170 QRect startRect(from.rect()); 00171 QRect targetRect(to.rect()); 00172 QSize pixmapSize = startRect.size().expandedTo(targetRect.size()); 00173 QRect toRect = QRect(QPoint(0,0), pixmapSize); 00174 targetRect.moveCenter(toRect.center()); 00175 startRect.moveCenter(toRect.center()); 00176 00177 //paint to in the center of from 00178 QColor color; 00179 color.setAlphaF(amount); 00180 00181 // If the native paint engine supports Porter/Duff compositing and CompositionMode_Plus 00182 QPaintEngine *paintEngine = from.paintEngine(); 00183 if (paintEngine && 00184 paintEngine->hasFeature(QPaintEngine::PorterDuff) && 00185 paintEngine->hasFeature(QPaintEngine::BlendModes)) { 00186 QPixmap startPixmap(pixmapSize); 00187 startPixmap.fill(Qt::transparent); 00188 00189 QPixmap targetPixmap(pixmapSize); 00190 targetPixmap.fill(Qt::transparent); 00191 00192 QPainter p; 00193 p.begin(&targetPixmap); 00194 p.drawPixmap(targetRect, to); 00195 p.setCompositionMode(QPainter::CompositionMode_DestinationIn); 00196 p.fillRect(targetRect, color); 00197 p.end(); 00198 00199 p.begin(&startPixmap); 00200 p.drawPixmap(startRect, from); 00201 p.setCompositionMode(QPainter::CompositionMode_DestinationOut); 00202 p.fillRect(startRect, color); 00203 p.setCompositionMode(QPainter::CompositionMode_Plus); 00204 p.drawPixmap(targetRect, targetPixmap); 00205 p.end(); 00206 00207 return startPixmap; 00208 } 00209 #if defined(Q_WS_X11) && defined(HAVE_XRENDER) 00210 // We have Xrender support 00211 else if (paintEngine && paintEngine->hasFeature(QPaintEngine::PorterDuff)) { 00212 // QX11PaintEngine doesn't implement CompositionMode_Plus in Qt 4.3, 00213 // which we need to be able to do a transition from one pixmap to 00214 // another. 00215 // 00216 // In order to avoid the overhead of converting the pixmaps to images 00217 // and doing the operation entirely in software, this function has a 00218 // specialized path for X11 that uses Xrender directly to do the 00219 // transition. This operation can be fully accelerated in HW. 00220 // 00221 // This specialization can be removed when QX11PaintEngine supports 00222 // CompositionMode_Plus. 00223 QPixmap source(targetPixmap), destination(startPixmap); 00224 00225 source.detach(); 00226 destination.detach(); 00227 00228 Display *dpy = QX11Info::display(); 00229 00230 XRenderPictFormat *format = XRenderFindStandardFormat(dpy, PictStandardA8); 00231 XRenderPictureAttributes pa; 00232 pa.repeat = 1; // RepeatNormal 00233 00234 // Create a 1x1 8 bit repeating alpha picture 00235 Pixmap pixmap = XCreatePixmap(dpy, destination.handle(), 1, 1, 8); 00236 Picture alpha = XRenderCreatePicture(dpy, pixmap, format, CPRepeat, &pa); 00237 XFreePixmap(dpy, pixmap); 00238 00239 // Fill the alpha picture with the opacity value 00240 XRenderColor xcolor; 00241 xcolor.alpha = quint16(0xffff * amount); 00242 XRenderFillRectangle(dpy, PictOpSrc, alpha, &xcolor, 0, 0, 1, 1); 00243 00244 // Reduce the alpha of the destination with 1 - opacity 00245 XRenderComposite(dpy, PictOpOutReverse, alpha, None, destination.x11PictureHandle(), 00246 0, 0, 0, 0, 0, 0, destination.width(), destination.height()); 00247 00248 // Add source * opacity to the destination 00249 XRenderComposite(dpy, PictOpAdd, source.x11PictureHandle(), alpha, 00250 destination.x11PictureHandle(), 00251 toRect.x(), toRect.y(), 0, 0, 0, 0, destination.width(), destination.height()); 00252 00253 XRenderFreePicture(dpy, alpha); 00254 return destination; 00255 } 00256 #endif 00257 else { 00258 // Fall back to using QRasterPaintEngine to do the transition. 00259 QImage under(pixmapSize, QImage::Format_ARGB32_Premultiplied); 00260 under.fill(Qt::transparent); 00261 QImage over(pixmapSize, QImage::Format_ARGB32_Premultiplied); 00262 over.fill(Qt::transparent); 00263 00264 QPainter p; 00265 p.begin(&over); 00266 p.drawPixmap(targetRect, to); 00267 p.setCompositionMode(QPainter::CompositionMode_DestinationIn); 00268 p.fillRect(over.rect(), color); 00269 p.end(); 00270 00271 p.begin(&under); 00272 p.drawPixmap(startRect, from); 00273 p.setCompositionMode(QPainter::CompositionMode_DestinationOut); 00274 p.fillRect(startRect, color); 00275 p.setCompositionMode(QPainter::CompositionMode_Plus); 00276 p.drawImage(toRect.topLeft(), over); 00277 p.end(); 00278 00279 return QPixmap::fromImage(under); 00280 } 00281 } 00282 00283 } // PaintUtils namespace 00284 00285 } // Plasma namespace 00286
KDE 4.6 API Reference