Warning, file /system/qtcurve/qt5/kwin/qtcurveshadowcache.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*****************************************************************************
0002  *   Copyright 2007 - 2010 Craig Drummond <craig.p.drummond@gmail.com>       *
0003  *   Copyright 2013 - 2015 Yichao Yu <yyc1992@gmail.com>                     *
0004  *                                                                           *
0005  *   This program is free software; you can redistribute it and/or modify    *
0006  *   it under the terms of the GNU Lesser General Public License as          *
0007  *   published by the Free Software Foundation; either version 2.1 of the    *
0008  *   License, or (at your option) version 3, or any later version accepted   *
0009  *   by the membership of KDE e.V. (or its successor approved by the         *
0010  *   membership of KDE e.V.), which shall act as a proxy defined in          *
0011  *   Section 6 of version 3 of the license.                                  *
0012  *                                                                           *
0013  *   This program is distributed in the hope that it will be useful,         *
0014  *   but WITHOUT ANY WARRANTY; without even the implied warranty of          *
0015  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU       *
0016  *   Lesser General Public License for more details.                         *
0017  *                                                                           *
0018  *   You should have received a copy of the GNU Lesser General Public        *
0019  *   License along with this library. If not,                                *
0020  *   see <http://www.gnu.org/licenses/>.                                     *
0021  *****************************************************************************/
0022 
0023 //////////////////////////////////////////////////////////////////////////////
0024 // Taken from: oxygenshadowcache.cpp
0025 // handles caching of TileSet objects to draw shadows
0026 // -------------------
0027 //
0028 // Copyright (c) 2009 Hugo Pereira Da Costa <hugo.pereira@free.fr>
0029 //
0030 // Permission is hereby granted, free of charge, to any person obtaining a copy
0031 // of this software and associated documentation files (the "Software"), to
0032 // deal in the Software without restriction, including without limitation the
0033 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
0034 // sell copies of the Software, and to permit persons to whom the Software is
0035 // furnished to do so, subject to the following conditions:
0036 //
0037 // The above copyright notice and this permission notice shall be included in
0038 // all copies or substantial portions of the Software.
0039 //
0040 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0041 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0042 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
0043 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
0044 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
0045 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
0046 // IN THE SOFTWARE.
0047 //////////////////////////////////////////////////////////////////////////////
0048 
0049 #include <kdeversion.h>
0050 
0051 #include <KColorUtils>
0052 #include <KColorScheme>
0053 #include <QPainter>
0054 
0055 #include <style/qtcurve.h>
0056 
0057 #include "qtcurveshadowcache.h"
0058 #include "qtcurveclient.h"
0059 #include "qtcurvehandler.h"
0060 
0061 namespace QtCurve {
0062 namespace KWin {
0063 
0064 static bool lowThreshold(const QColor &color)
0065 {
0066     QColor darker = KColorScheme::shade(color, KColorScheme::MidShade, 0.5);
0067     return KColorUtils::luma(darker) > KColorUtils::luma(color);
0068 }
0069 
0070 static QColor backgroundTopColor(const QColor &color)
0071 {
0072 
0073     if(lowThreshold(color)) return KColorScheme::shade(color, KColorScheme::MidlightShade, 0.0);
0074     qreal my = KColorUtils::luma(KColorScheme::shade(color, KColorScheme::LightShade, 0.0));
0075     qreal by = KColorUtils::luma(color);
0076     return KColorUtils::shade(color, (my - by) * 0.9/*_bgcontrast*/);
0077 
0078 }
0079 
0080 static QColor backgroundBottomColor(const QColor &color)
0081 {
0082     QColor midColor = KColorScheme::shade(color, KColorScheme::MidShade, 0.0);
0083     if(lowThreshold(color)) return midColor;
0084 
0085     qreal by = KColorUtils::luma(color);
0086     qreal my = KColorUtils::luma(midColor);
0087     return KColorUtils::shade(color, (my - by) * 0.9/*_bgcontrast*/ * 0.85);
0088 }
0089 
0090 static QColor calcLightColor(const QColor &color)
0091 {
0092     return KColorScheme::shade(color, KColorScheme::LightShade, 0.7/*_contrast*/);
0093 }
0094 
0095 QtCurveShadowCache::QtCurveShadowCache()
0096                   : m_activeShadowConfig(ShadowConfig(QPalette::Active))
0097                   , m_inactiveShadowConfig(ShadowConfig(QPalette::Inactive))
0098 {
0099     m_shadowCache.setMaxCost(1<<6);
0100 }
0101 
0102 bool QtCurveShadowCache::shadowConfigChanged(const ShadowConfig &other) const
0103 {
0104     const auto &local = (other.colorGroup() == QPalette::Active ?
0105                          m_activeShadowConfig : m_inactiveShadowConfig);
0106     return !(local == other);
0107 }
0108 
0109 void QtCurveShadowCache::setShadowConfig(const ShadowConfig &other)
0110 {
0111     auto &local = (other.colorGroup() == QPalette::Active ?
0112                    m_activeShadowConfig : m_inactiveShadowConfig);
0113     local = other;
0114     reset();
0115 }
0116 
0117 TileSet*
0118 QtCurveShadowCache::tileSet(const QtCurveClient *client, bool roundAllCorners)
0119 {
0120     Key key(client);
0121     int hash(key.hash());
0122 
0123     if (m_shadowCache.contains(hash))
0124         return m_shadowCache.object(hash);
0125 
0126     qreal   size(shadowSize());
0127     TileSet *tileSet = new TileSet(shadowPixmap(client, key.active, roundAllCorners), size, size, 1, 1);
0128 
0129     m_shadowCache.insert(hash, tileSet);
0130     return tileSet;
0131 }
0132 
0133 QPixmap QtCurveShadowCache::shadowPixmap(const QtCurveClient *client, bool active, bool roundAllCorners) const
0134 {
0135     Key      key(client);
0136     QPalette palette(client->widget()->palette());
0137     QColor   color(palette.color(client->widget()->backgroundRole()));
0138 
0139     return simpleShadowPixmap(color, active, roundAllCorners);
0140 }
0141 
0142 QPixmap QtCurveShadowCache::simpleShadowPixmap(const QColor &color, bool active, bool roundAllCorners) const
0143 {
0144     static const qreal fixedSize = 25.5;
0145 
0146     const ShadowConfig &shadowConfig(active ? m_activeShadowConfig : m_inactiveShadowConfig);
0147 
0148     // offsets are scaled with the shadow size
0149     // so that the ratio Top-shadow/Bottom-shadow is kept constant when shadow size is changed
0150     qreal   size(shadowSize()),
0151             shadowSize(shadowConfig.shadowSize());
0152     QPixmap shadow(size*2, size*2);
0153 
0154     shadow.fill(Qt::transparent);
0155 
0156     QPainter p(&shadow);
0157 
0158     p.setRenderHint(QPainter::Antialiasing);
0159     p.setPen(Qt::NoPen);
0160 
0161     if (shadowSize) {
0162         if (ShadowConfig::SH_ACTIVE == shadowConfig.shadowType()) {
0163             {
0164                 // inner (shark) gradient
0165                 const qreal gradientSize = qMin(shadowSize,
0166                                                 (shadowSize + fixedSize) / 2);
0167                 const qreal hoffset = (shadowConfig.horizontalOffset() / 100. *
0168                                        gradientSize / fixedSize);
0169                 const qreal voffset = (shadowConfig.verticalOffset() / 100. *
0170                                        gradientSize / fixedSize);
0171 
0172                 QRadialGradient rg = QRadialGradient(size + 12. * hoffset,
0173                                                      size + 12. * voffset,
0174                                                      gradientSize);
0175                 rg.setColorAt(1, Qt::transparent);
0176 
0177                 // gaussian shadow is used
0178                 int nPoints(10 * gradientSize / fixedSize);
0179                 Gaussian f(0.85, 0.25);
0180                 QColor c = shadowConfig.innerColor();
0181                 for (int i = 0;i < nPoints;i++) {
0182                     qreal x = qreal(i) / nPoints;
0183                     c.setAlphaF(f(x));
0184                     rg.setColorAt(x, c);
0185                 }
0186 
0187                 p.setBrush(rg);
0188                 renderGradient(p, shadow.rect(), rg, roundAllCorners);
0189             }
0190 
0191             {
0192                 // outer (spread) gradient
0193                 const qreal gradientSize = shadowSize;
0194                 const qreal hoffset = (shadowConfig.horizontalOffset() / 100. *
0195                                        gradientSize / fixedSize);
0196                 const qreal voffset = (shadowConfig.verticalOffset() / 100. *
0197                                        gradientSize / fixedSize);
0198 
0199                 QRadialGradient rg = QRadialGradient(size + 12. * hoffset,
0200                                                      size + 12. * voffset,
0201                                                      gradientSize);
0202                 rg.setColorAt(1, Qt::transparent);
0203 
0204                 // gaussian shadow is used
0205                 int nPoints(10 * gradientSize / fixedSize);
0206                 Gaussian f(0.46, 0.42);
0207                 QColor c = shadowConfig.outerColor();
0208                 for (int i = 0;i < nPoints;i++) {
0209                     qreal x = qreal(i) / nPoints;
0210                     c.setAlphaF(f(x));
0211                     rg.setColorAt(x, c);
0212                 }
0213                 p.setBrush(rg);
0214                 p.drawRect(shadow.rect());
0215             }
0216         } else {
0217             {
0218                 // inner (sharp gradient)
0219                 const qreal gradientSize = qMin(shadowSize, fixedSize);
0220                 const qreal hoffset = (shadowConfig.horizontalOffset() / 100. *
0221                                        gradientSize / fixedSize);
0222                 const qreal voffset = (shadowConfig.verticalOffset() / 100. *
0223                                        gradientSize / fixedSize);
0224 
0225                 QRadialGradient rg = QRadialGradient(size + hoffset,
0226                                                      size + voffset,
0227                                                      gradientSize);
0228                 rg.setColorAt(1, Qt::transparent);
0229 
0230                 // parabolic shadow is used
0231                 int nPoints(10 * gradientSize / fixedSize);
0232                 Parabolic f(0.85, 0.22);
0233                 QColor c = shadowConfig.outerColor();
0234                 for (int i = 0;i < nPoints;i++) {
0235                     qreal x = qreal(i) / nPoints;
0236                     c.setAlphaF(f(x));
0237                     rg.setColorAt(x, c);
0238                 }
0239 
0240                 p.setBrush(rg);
0241                 renderGradient(p, shadow.rect(), rg, roundAllCorners);
0242             }
0243 
0244             {
0245                 // mid gradient
0246                 const qreal gradientSize = qMin(shadowSize,
0247                                                 (shadowSize +
0248                                                  2 * fixedSize) / 3);
0249                 const qreal hoffset = (shadowConfig.horizontalOffset() / 100. *
0250                                        gradientSize / fixedSize);
0251                 const qreal voffset = (shadowConfig.verticalOffset() / 100. *
0252                                        gradientSize / fixedSize);
0253 
0254                 // gaussian shadow is used
0255                 QRadialGradient rg = QRadialGradient(size + 8. * hoffset,
0256                                                      size + 8. * voffset,
0257                                                      gradientSize);
0258                 rg.setColorAt(1, Qt::transparent);
0259 
0260                 int nPoints(10 * gradientSize / fixedSize);
0261                 Gaussian f(0.54, 0.21);
0262                 QColor c = shadowConfig.outerColor();
0263                 for (int i = 0;i < nPoints;i++) {
0264                     qreal x = qreal(i) / nPoints;
0265                     c.setAlphaF(f(x));
0266                     rg.setColorAt(x, c);
0267                 }
0268 
0269                 p.setBrush(rg);
0270                 p.drawRect(shadow.rect());
0271             }
0272             {
0273                 // outer (spread) gradient
0274                 const qreal gradientSize = shadowSize;
0275                 const qreal hoffset = (shadowConfig.horizontalOffset() / 100. *
0276                                        gradientSize / fixedSize);
0277                 const qreal voffset = (shadowConfig.verticalOffset() / 100. *
0278                                        gradientSize / fixedSize);
0279 
0280                 // gaussian shadow is used
0281                 QRadialGradient rg = QRadialGradient(size + 20. * hoffset,
0282                                                      size + 20. * voffset,
0283                                                      gradientSize);
0284                 rg.setColorAt(1, Qt::transparent);
0285 
0286                 int nPoints(20 * gradientSize / fixedSize);
0287                 Gaussian f(0.155, 0.445);
0288                 QColor c = shadowConfig.outerColor();
0289                 for (int i = 0;i < nPoints;i++) {
0290                     qreal x = qreal(i) / nPoints;
0291                     c.setAlphaF(f(x));
0292                     rg.setColorAt(x, c);
0293                 }
0294 
0295                 p.setBrush(rg);
0296                 p.drawRect(shadow.rect());
0297             }
0298         }
0299     }
0300 
0301     // draw the corner of the window - actually all 4 corners as one circle
0302     // this is all fixedSize. Does not scale with shadow size
0303     QLinearGradient lg = QLinearGradient(0.0, size-4.5, 0.0, size+4.5);
0304     lg.setColorAt(0.0, calcLightColor(backgroundTopColor(color)));
0305     lg.setColorAt(0.51, backgroundBottomColor(color));
0306     lg.setColorAt(1.0, backgroundBottomColor(color));
0307 
0308     p.setBrush(lg);
0309     p.drawEllipse(QRectF(size-4, size-4, 8, 8));
0310     p.end();
0311     return shadow;
0312 }
0313 
0314 void QtCurveShadowCache::renderGradient(QPainter &p, const QRectF &rect, const QRadialGradient &rg, bool hasBorder) const
0315 {
0316     if( hasBorder )
0317     {
0318         p.setBrush( rg );
0319         p.drawRect( rect );
0320         return;
0321     }
0322 
0323 
0324     qreal          size(rect.width() / 2.0),
0325                    hoffset(rg.center().x() - size),
0326                    voffset(rg.center().y() - size),
0327                    radius(rg.radius());
0328     QGradientStops stops(rg.stops());
0329 
0330     // draw ellipse for the upper rect
0331     {
0332         QRectF rect(hoffset, voffset, 2*size-hoffset, size);
0333         p.setBrush(rg);
0334         p.drawRect(rect);
0335     }
0336 
0337     // draw square gradients for the lower rect
0338     {
0339         // vertical lines
0340         QRectF          rect(hoffset, size+voffset, 2*size-hoffset, 4);
0341         QLinearGradient lg(hoffset, 0.0, 2*size+hoffset, 0.0);
0342 
0343         for(int i = 0; i<stops.size(); i++)
0344         {
0345             QColor c(stops[i].second);
0346             qreal  xx(stops[i].first*radius);
0347 
0348             lg.setColorAt((size - xx) / (2. * size), c);
0349             lg.setColorAt((size + xx) / (2. * size), c);
0350         }
0351 
0352         p.setBrush(lg);
0353         p.drawRect(rect);
0354     }
0355 
0356     {
0357         // horizontal line
0358         QRectF          rect(size-4+hoffset, size+voffset, 8, size);
0359         QLinearGradient lg = QLinearGradient(0, voffset, 0, 2*size+voffset);
0360 
0361         for(int i = 0; i<stops.size(); i++)
0362         {
0363             QColor c(stops[i].second);
0364             qreal  xx(stops[i].first*radius);
0365 
0366             lg.setColorAt((size + xx) / (2. * size), c);
0367         }
0368 
0369         p.setBrush(lg);
0370         p.drawRect(rect);
0371     }
0372 
0373     {
0374       // bottom-left corner
0375         QRectF          rect(hoffset, size+4+voffset, size-4, size);
0376         QRadialGradient rg = QRadialGradient(size+hoffset-4, size+4+voffset, radius);
0377 
0378         for(int i = 0; i<stops.size(); i++)
0379         {
0380             QColor c(stops[i].second);
0381             qreal  xx(stops[i].first -4.0/rg.radius());
0382 
0383             if(xx<0 && i < stops.size()-1)
0384             {
0385                 qreal x1(stops[i+1].first -4.0/rg.radius());
0386                 c = KColorUtils::mix(c, stops[i+1].second, -xx/(x1-xx));
0387                 xx = 0;
0388             }
0389 
0390             rg.setColorAt(xx, c);
0391         }
0392 
0393         p.setBrush(rg);
0394         p.drawRect(rect);
0395     }
0396 
0397     {
0398       // bottom-right corner
0399         QRectF          rect(size+4+hoffset, size+4+voffset, size-4, size);
0400         QRadialGradient rg = QRadialGradient(size+hoffset+4, size+4+voffset, radius);
0401 
0402         for(int i = 0; i<stops.size(); i++)
0403         {
0404             QColor c(stops[i].second);
0405             qreal  xx(stops[i].first -4.0/rg.radius());
0406 
0407             if(xx<0 && i < stops.size()-1)
0408             {
0409                 qreal x1(stops[i+1].first -4.0/rg.radius());
0410                 c = KColorUtils::mix(c, stops[i+1].second, -xx/(x1-xx));
0411                 xx = 0;
0412             }
0413 
0414             rg.setColorAt(xx, c);
0415         }
0416 
0417         p.setBrush(rg);
0418         p.drawRect(rect);
0419     }
0420 }
0421 
0422 QtCurveShadowCache::Key::Key(const QtCurveClient *client)
0423                        : active(client->isActive())
0424                        , isShade(client->isShade())
0425 {
0426 }
0427 
0428 }
0429 }