From afdb5e84a0d9756caa6850f91f9d4d021a23918f Mon Sep 17 00:00:00 2001
From: Marco Martin <notmart@gmail.com>
Date: Wed, 5 Mar 2008 21:03:27 +0000
Subject: [PATCH] reworked how shaped windows with svg backgrounds are
 obtained: there is a new function PanelSvg::mask() that returns a qbitmap of
 the areas of the svg with alpha=0 that can be used to create the mask of the
 window, at the moment used in tooltip and dialog (krunner still to come). so
 now windows that uses svg backgrounds should always set PanelSvg::mask() as
 their own mask, regardless if composite is active or not. In this commit
 there are also two (identical) svgs for opaque tooltips and dialogs with
 pixelated rounded borders that looks good without antialiasing (and unlike
 the previous version they are vector based now).

svn path=/trunk/KDE/kdebase/workspace/libs/plasma/; revision=782727
---
 dialog.cpp          |   3 +
 svgpanel.cpp        | 161 +++++++++++++++++++++++++-------------------
 svgpanel.h          |   6 ++
 theme.cpp           |   5 ++
 theme.h             |   5 ++
 widgets/tooltip.cpp |  22 +-----
 6 files changed, 113 insertions(+), 89 deletions(-)

diff --git a/dialog.cpp b/dialog.cpp
index 0bfb969da..cd8da18a9 100644
--- a/dialog.cpp
+++ b/dialog.cpp
@@ -28,6 +28,7 @@
 #ifdef Q_WS_X11
 #include <QX11Info>
 #endif
+#include <QBitmap>
 #include <QGraphicsView>
 #include <QtGui/QGraphicsSceneEvent>
 
@@ -95,6 +96,8 @@ void Dialog::paintEvent(QPaintEvent *e)
 void Dialog::resizeEvent(QResizeEvent *e)
 {
     d->background->resize(e->size());
+
+    setMask(d->background->mask());
 }
 
 void Dialog::position(QGraphicsSceneEvent *event, const QRectF boundingRect, QPointF scenePos)
diff --git a/svgpanel.cpp b/svgpanel.cpp
index 32fc89d93..d5d75d3fb 100644
--- a/svgpanel.cpp
+++ b/svgpanel.cpp
@@ -22,6 +22,7 @@
 
 #include <QPainter>
 #include <QSize>
+#include <QBitmap>
 
 #include <KDebug>
 
@@ -42,6 +43,8 @@ public:
         delete cachedBackground;
     }
 
+    void generateBackground();
+
     BorderFlags bFlags;
     QPixmap *cachedBackground;
     Svg *background;
@@ -153,32 +156,41 @@ qreal SvgPanel::marginSize(const Plasma::MarginEdge edge) const
     }
 }
 
-void SvgPanel::paint(QPainter* painter, const QRectF& rect)
+QBitmap SvgPanel::mask() const
 {
-    bool origined = d->bFlags & ContentAtOrigin;
-    const int topWidth = d->background->elementSize("top").width();
-    const int leftHeight = d->background->elementSize("left").height();
-    const int topOffset = origined ? 0 - d->topHeight : 0;
-    const int leftOffset = origined ? 0 - d->leftWidth : 0;
-
     if (!d->cachedBackground) {
-        const int contentWidth = d->panelSize.width() - d->leftWidth  - d->rightWidth;
-        const int contentHeight = d->panelSize.height() - d->topHeight  - d->bottomHeight;
+        d->generateBackground();
+    }
+
+    return d->cachedBackground->alphaChannel().createMaskFromColor(Qt::black);
+}
+
+void SvgPanel::Private::generateBackground()
+{
+    bool origined = bFlags & ContentAtOrigin;
+    const int topWidth = background->elementSize("top").width();
+    const int leftHeight = background->elementSize("left").height();
+    const int topOffset = origined ? 0 - topHeight : 0;
+    const int leftOffset = origined ? 0 - leftWidth : 0;
+
+    if (!cachedBackground) {
+        const int contentWidth = panelSize.width() - leftWidth  - rightWidth;
+        const int contentHeight = panelSize.height() - topHeight  - bottomHeight;
         int contentTop = 0;
         int contentLeft = 0;
         int rightOffset = contentWidth;
         int bottomOffset = contentHeight;
 
-        delete d->cachedBackground;
-        d->cachedBackground = new QPixmap(d->leftWidth + contentWidth + d->rightWidth,
-                                          d->topHeight + contentHeight + d->bottomHeight);
-        d->cachedBackground->fill(Qt::transparent);
-        QPainter p(d->cachedBackground);
+        delete cachedBackground;
+        cachedBackground = new QPixmap(leftWidth + contentWidth + rightWidth,
+                                          topHeight + contentHeight + bottomHeight);
+        cachedBackground->fill(Qt::transparent);
+        QPainter p(cachedBackground);
         p.setCompositionMode(QPainter::CompositionMode_Source);
         p.setRenderHint(QPainter::SmoothPixmapTransform);
 
         if (origined) {
-            p.translate(d->leftWidth, d->topHeight);
+            p.translate(leftWidth, topHeight);
         }
 
         //FIXME: This is a hack to fix a drawing problems with svg files where a thin transparent border is drawn around the svg image.
@@ -188,124 +200,124 @@ void SvgPanel::paint(QPainter* painter, const QRectF& rect)
 
        //CENTER
        if (contentHeight > 0 && contentWidth > 0) {
-           QSizeF scaledSize = QSizeF(d->panelSize.width() -
-                            (d->leftWidth + d->rightWidth) +
-                            d->panelSize.width()*(((qreal)(d->leftWidth + d->rightWidth)) / d->panelSize.width()),
-                            d->panelSize.height() -
-                            (d->topHeight + d->bottomHeight) +
-                            d->panelSize.height()*(((qreal)(d->topHeight + d->bottomHeight)) / d->panelSize.height()));
+           QSizeF scaledSize = QSizeF(panelSize.width() -
+                            (leftWidth + rightWidth) +
+                            panelSize.width()*(((qreal)(leftWidth + rightWidth)) / panelSize.width()),
+                            panelSize.height() -
+                            (topHeight + bottomHeight) +
+                            panelSize.height()*(((qreal)(topHeight + bottomHeight)) / panelSize.height()));
 
-           d->background->resize(scaledSize.width(), scaledSize.height());
-           d->background->paint(&p, QRect(contentLeft - d->leftWidth, contentTop - d->topHeight,
-                                          contentWidth + d->leftWidth*2, contentHeight + d->topHeight*2),
+           background->resize(scaledSize.width(), scaledSize.height());
+           background->paint(&p, QRect(contentLeft - leftWidth, contentTop - topHeight,
+                                          contentWidth + leftWidth*2, contentHeight + topHeight*2),
                                "center");
-           d->background->resize();
+           background->resize();
        }
 
         // Corners
-        if (d->bFlags & DrawTopBorder) {
+        if (bFlags & DrawTopBorder) {
             if (!origined) {
-                contentTop = d->topHeight;
-                bottomOffset += d->topHeight;
+                contentTop = topHeight;
+                bottomOffset += topHeight;
             }
 
-            if (d->bFlags & DrawLeftBorder) {
-                d->background->paint(&p, QRect(leftOffset, topOffset, d->leftWidth, d->topHeight), "topleft");
+            if (bFlags & DrawLeftBorder) {
+                background->paint(&p, QRect(leftOffset, topOffset, leftWidth, topHeight), "topleft");
 
                 if (!origined) {
-                    contentLeft = d->leftWidth;
-                    rightOffset = contentWidth + d->leftWidth;
+                    contentLeft = leftWidth;
+                    rightOffset = contentWidth + leftWidth;
                 }
             }
 
-            if (d->bFlags & DrawRightBorder) {
-                d->background->paint(&p, QRect(rightOffset, topOffset, d->rightWidth, d->topHeight), "topright");
+            if (bFlags & DrawRightBorder) {
+                background->paint(&p, QRect(rightOffset, topOffset, rightWidth, topHeight), "topright");
             }
         }
 
-        if (d->bFlags & DrawBottomBorder) {
-            if (d->bFlags & DrawLeftBorder) {
-                d->background->paint(&p, QRect(leftOffset, bottomOffset, d->leftWidth, d->bottomHeight), "bottomleft");
+        if (bFlags & DrawBottomBorder) {
+            if (bFlags & DrawLeftBorder) {
+                background->paint(&p, QRect(leftOffset, bottomOffset, leftWidth, bottomHeight), "bottomleft");
 
                 if (!origined) {
-                    contentLeft = d->leftWidth;
-                    rightOffset = contentWidth + d->leftWidth;
+                    contentLeft = leftWidth;
+                    rightOffset = contentWidth + leftWidth;
                 }
             }
 
-            if (d->bFlags & DrawRightBorder) {
-                d->background->paint(&p, QRect(rightOffset, bottomOffset, d->rightWidth, d->bottomHeight), "bottomright");
+            if (bFlags & DrawRightBorder) {
+                background->paint(&p, QRect(rightOffset, bottomOffset, rightWidth, bottomHeight), "bottomright");
             }
         }
 
         // Sides
-        if (d->stretchBorders) {
-            if (d->bFlags & DrawLeftBorder) {
-                d->background->paint(&p, QRect(leftOffset, contentTop, d->leftWidth, contentHeight), "left");
+        if (stretchBorders) {
+            if (bFlags & DrawLeftBorder) {
+                background->paint(&p, QRect(leftOffset, contentTop, leftWidth, contentHeight), "left");
             }
 
-            if (d->bFlags & DrawRightBorder) {
-                d->background->paint(&p, QRect(rightOffset, contentTop, d->rightWidth, contentHeight), "right");
+            if (bFlags & DrawRightBorder) {
+                background->paint(&p, QRect(rightOffset, contentTop, rightWidth, contentHeight), "right");
             }
 
-            if (d->bFlags & DrawTopBorder) {
-                d->background->paint(&p, QRect(contentLeft, topOffset, contentWidth, d->topHeight), "top");
+            if (bFlags & DrawTopBorder) {
+                background->paint(&p, QRect(contentLeft, topOffset, contentWidth, topHeight), "top");
             }
 
-            if (d->bFlags & DrawBottomBorder) {
-                d->background->paint(&p, QRect(contentLeft, bottomOffset, contentWidth, d->bottomHeight), "bottom");
+            if (bFlags & DrawBottomBorder) {
+                background->paint(&p, QRect(contentLeft, bottomOffset, contentWidth, bottomHeight), "bottom");
             }
         } else {
-            if (d->bFlags & DrawLeftBorder) {
-                QPixmap left(d->leftWidth, leftHeight);
+            if (bFlags & DrawLeftBorder) {
+                QPixmap left(leftWidth, leftHeight);
                 left.fill(Qt::transparent);
 
                 {
                     QPainter sidePainter(&left);
                     sidePainter.setCompositionMode(QPainter::CompositionMode_Source);
-                    d->background->paint(&sidePainter, QPoint(0, 0), "left");
+                    background->paint(&sidePainter, QPoint(0, 0), "left");
                 }
 
-                p.drawTiledPixmap(QRect(leftOffset, contentTop, d->leftWidth, contentHeight), left);
+                p.drawTiledPixmap(QRect(leftOffset, contentTop, leftWidth, contentHeight), left);
             }
 
-            if (d->bFlags & DrawRightBorder) {
-                QPixmap right(d->rightWidth, leftHeight);
+            if (bFlags & DrawRightBorder) {
+                QPixmap right(rightWidth, leftHeight);
                 right.fill(Qt::transparent);
 
                 {
                     QPainter sidePainter(&right);
                     sidePainter.setCompositionMode(QPainter::CompositionMode_Source);
-                    d->background->paint(&sidePainter, QPoint(0, 0), "right");
+                    background->paint(&sidePainter, QPoint(0, 0), "right");
                 }
 
-                p.drawTiledPixmap(QRect(rightOffset, contentTop, d->rightWidth, contentHeight), right);
+                p.drawTiledPixmap(QRect(rightOffset, contentTop, rightWidth, contentHeight), right);
             }
 
-            if (d->bFlags & DrawTopBorder) {
-                QPixmap top(topWidth, d->topHeight);
+            if (bFlags & DrawTopBorder) {
+                QPixmap top(topWidth, topHeight);
                 top.fill(Qt::transparent);
 
                 {
                     QPainter sidePainter(&top);
                     sidePainter.setCompositionMode(QPainter::CompositionMode_Source);
-                    d->background->paint(&sidePainter, QPoint(0, 0), "top");
+                    background->paint(&sidePainter, QPoint(0, 0), "top");
                 }
 
-                p.drawTiledPixmap(QRect(contentLeft, topOffset, contentWidth, d->topHeight), top);
+                p.drawTiledPixmap(QRect(contentLeft, topOffset, contentWidth, topHeight), top);
             }
 
-            if (d->bFlags & DrawBottomBorder) {
-                QPixmap bottom(topWidth, d->bottomHeight);
+            if (bFlags & DrawBottomBorder) {
+                QPixmap bottom(topWidth, bottomHeight);
                 bottom.fill(Qt::transparent);
 
                 {
                     QPainter sidePainter(&bottom);
                     sidePainter.setCompositionMode(QPainter::CompositionMode_Source);
-                    d->background->paint(&sidePainter, QPoint(0, 0), "bottom");
+                    background->paint(&sidePainter, QPoint(0, 0), "bottom");
                 }
 
-                p.drawTiledPixmap(QRect(contentLeft, bottomOffset, contentWidth, d->bottomHeight), bottom);
+                p.drawTiledPixmap(QRect(contentLeft, bottomOffset, contentWidth, bottomHeight), bottom);
             }
         }
 
@@ -313,9 +325,22 @@ void SvgPanel::paint(QPainter* painter, const QRectF& rect)
         //resize(contentWidth, contentHeight);
         //paint(&p, QRect(contentLeft, contentTop, contentWidth, contentHeight), "center");
    }
+}
 
-   //p2->drawPixmap(paintRect, *cachedBackground, paintRect.translated(-leftOffset,-topOffset));
-   painter->drawPixmap(rect, *d->cachedBackground, rect.translated(-d->pos.x()-leftOffset,-d->pos.y()-topOffset));
+void SvgPanel::paint(QPainter* painter, const QRectF& rect)
+{
+    if (!d->cachedBackground) {
+        d->generateBackground();
+    }
+
+    //FIXME: this is redundant with generatebackground for now
+    bool origined = d->bFlags & ContentAtOrigin;
+    const int topWidth = d->background->elementSize("top").width();
+    const int leftHeight = d->background->elementSize("left").height();
+    const int topOffset = origined ? 0 - d->topHeight : 0;
+    const int leftOffset = origined ? 0 - d->leftWidth : 0;
+
+    painter->drawPixmap(rect, *d->cachedBackground, rect.translated(-d->pos.x()-leftOffset,-d->pos.y()-topOffset));
 }
 
 void SvgPanel::updateSizes()
diff --git a/svgpanel.h b/svgpanel.h
index da21c3b96..6b65f013d 100644
--- a/svgpanel.h
+++ b/svgpanel.h
@@ -122,6 +122,12 @@ class PLASMA_EXPORT SvgPanel : public QObject
          */
         QPointF pos() const;
 
+        /**
+         * Returns a monochrome mask that tightly contains the fully opaque areas of the svg
+         * @return a monochrome bitmap of opaque areas
+         */
+        QBitmap mask() const;
+
         /**
          * Paints the loaded SVG with the elements that represents the border
          * @arg painter the QPainter to use
diff --git a/theme.cpp b/theme.cpp
index 62e1e77af..b742de8c0 100644
--- a/theme.cpp
+++ b/theme.cpp
@@ -280,6 +280,11 @@ QFontMetrics Theme::fontMetrics() const
     return QFontMetrics(d->generalFont);
 }
 
+bool Theme::compositingActive() const
+{
+    return d->compositingActive;
+}
+
 }
 
 #include <theme.moc>
diff --git a/theme.h b/theme.h
index 39d76f4ee..6e5ceebbd 100644
--- a/theme.h
+++ b/theme.h
@@ -130,6 +130,11 @@ class PLASMA_EXPORT Theme : public QObject
          */
         Q_INVOKABLE QFontMetrics fontMetrics() const;
 
+        /**
+         * Returns if the window compositing is active or not
+         */
+        Q_INVOKABLE bool compositingActive() const;
+
     Q_SIGNALS:
         /**
          * Emitted when the user changes the theme. SVGs should be reloaded at
diff --git a/widgets/tooltip.cpp b/widgets/tooltip.cpp
index b15e0a540..ae5cdd6d8 100644
--- a/widgets/tooltip.cpp
+++ b/widgets/tooltip.cpp
@@ -346,20 +346,7 @@ void ToolTip::resizeEvent(QResizeEvent *e)
     QWidget::resizeEvent(e);
     d->background->resize(size());
 
-    if (KWindowSystem::compositingActive()) {
-        return;
-    }
-
-    QBitmap mask(width(), height());
-    QPainter maskPainter(&mask);
-
-    mask.fill(Qt::white);
-
-    maskPainter.setBrush(Qt::black);
-    maskPainter.setPen(Qt::black);
-
-    maskPainter.drawPath(roundedRectangle(mask.rect().adjusted(-1,-1,-1,-1), 10));
-    setMask(mask);
+    setMask(d->background->mask());
 }
 
 void ToolTip::paintEvent(QPaintEvent *e)
@@ -371,13 +358,6 @@ void ToolTip::paintEvent(QPaintEvent *e)
     painter.fillRect(rect(), Qt::transparent);
 
     d->background->paint(&painter, rect());
-
-    //Stroke border if there is no compositing
-    if (!KWindowSystem::compositingActive()) {
-        painter.setCompositionMode(QPainter::CompositionMode_SourceOver );
-        painter.setPen(Plasma::Theme::self()->textColor());
-        painter.drawPath(roundedRectangle(rect().adjusted(.5,.5,-.5,-.5), 10));
-    }
 }
 
 }