use a separate cache for each elementPrefix, this will speed up

rendering a lot if prefixes are switched very often. this will make
possible for instance to render the background of taskbar items with a
PanelSvg.
This behaviour is disabled by default, you can enable/disable it with
setCacheAllRenderedPanels(bool), get with cacheAllRenderedPanels() and
erase the entire cache with clearCache()

svn path=/trunk/KDE/kdebase/workspace/libs/plasma/; revision=799411
This commit is contained in:
Marco Martin 2008-04-21 14:01:46 +00:00
parent b175042a04
commit 85a1f0e516
2 changed files with 195 additions and 115 deletions

View File

@ -29,35 +29,25 @@
namespace Plasma namespace Plasma
{ {
class PanelSvg::Private class PanelData
{ {
public: public:
Private(PanelSvg *psvg) PanelData()
: q(psvg), : enabledBorders(PanelSvg::AllBorders),
enabledBorders(AllBorders),
cachedBackground(0), cachedBackground(0),
contentAtOrigin(false) contentAtOrigin(false)
{ {
} }
~Private() ~PanelData()
{ {
delete cachedBackground; delete cachedBackground;
} }
void generateBackground(); PanelSvg::EnabledBorders enabledBorders;
void updateSizes();
PanelSvg *q;
EnabledBorders enabledBorders;
QPixmap *cachedBackground; QPixmap *cachedBackground;
Svg *background;
QSizeF panelSize; QSizeF panelSize;
Location location;
QString prefix;
//measures //measures
int topHeight; int topHeight;
int leftWidth; int leftWidth;
@ -72,6 +62,36 @@ public:
bool contentAtOrigin : 1; bool contentAtOrigin : 1;
}; };
class PanelSvg::Private
{
public:
Private(PanelSvg *psvg)
: q(psvg),
cacheAll(false)
{
}
~Private()
{
delete background;
qDeleteAll(panels);
}
void generateBackground();
void updateSizes();
Location location;
QString prefix;
PanelSvg *q;
Svg *background;
bool cacheAll : 1;
QHash<QString, PanelData*> panels;
};
PanelSvg::PanelSvg(const QString& imagePath, QObject* parent) PanelSvg::PanelSvg(const QString& imagePath, QObject* parent)
: Svg(imagePath, parent), : Svg(imagePath, parent),
d(new Private(this)) d(new Private(this))
@ -79,8 +99,9 @@ PanelSvg::PanelSvg(const QString& imagePath, QObject* parent)
d->background = new Svg(imagePath, this); d->background = new Svg(imagePath, this);
connect(d->background, SIGNAL(repaintNeeded()), this, SLOT(updateSizes())); connect(d->background, SIGNAL(repaintNeeded()), this, SLOT(updateSizes()));
d->panels.insert(QString(), new PanelData());
d->updateSizes(); d->updateSizes();
d->panelSize = d->background->size(); d->panels[QString()]->panelSize = d->background->size();
} }
PanelSvg::~PanelSvg() PanelSvg::~PanelSvg()
@ -94,8 +115,10 @@ void PanelSvg::setImagePath(const QString& imagePath)
return; return;
} }
qDeleteAll(d->panels);
d->background->setImagePath(imagePath); d->background->setImagePath(imagePath);
setElementPrefix(prefix()); //setElementPrefix(prefix());
} }
QString PanelSvg::imagePath() const QString PanelSvg::imagePath() const
@ -105,17 +128,17 @@ QString PanelSvg::imagePath() const
void PanelSvg::setEnabledBorders(const EnabledBorders borders) void PanelSvg::setEnabledBorders(const EnabledBorders borders)
{ {
if (borders == d->enabledBorders) { if (borders == d->panels[d->prefix]->enabledBorders) {
return; return;
} }
d->enabledBorders = borders; d->panels[d->prefix]->enabledBorders = borders;
d->updateSizes(); d->updateSizes();
} }
PanelSvg::EnabledBorders PanelSvg::enabledBorders() const PanelSvg::EnabledBorders PanelSvg::enabledBorders() const
{ {
return d->enabledBorders; return d->panels[d->prefix]->enabledBorders;
} }
void PanelSvg::setElementPrefix(Plasma::Location location) void PanelSvg::setElementPrefix(Plasma::Location location)
@ -142,6 +165,8 @@ void PanelSvg::setElementPrefix(Plasma::Location location)
void PanelSvg::setElementPrefix(const QString & prefix) void PanelSvg::setElementPrefix(const QString & prefix)
{ {
const QString oldPrefix(d->prefix);
if (!d->background->hasElement(prefix + "-center")) { if (!d->background->hasElement(prefix + "-center")) {
d->prefix.clear(); d->prefix.clear();
} else { } else {
@ -149,13 +174,23 @@ void PanelSvg::setElementPrefix(const QString & prefix)
if (!d->prefix.isEmpty()) { if (!d->prefix.isEmpty()) {
d->prefix += '-'; d->prefix += '-';
} }
}
if (oldPrefix == d->prefix && d->panels[oldPrefix]) {
return;
}
if (!d->cacheAll) {
delete d->panels[oldPrefix];
d->panels.remove(oldPrefix);
}
if (!d->panels.contains(d->prefix)) {
d->panels.insert(d->prefix, new PanelData());
} }
d->location = Floating; d->location = Floating;
if (d->cachedBackground) {
d->updateSizes();
}
} }
QString PanelSvg::prefix() QString PanelSvg::prefix()
@ -168,11 +203,11 @@ QString PanelSvg::prefix()
void PanelSvg::resize(const QSizeF& size) void PanelSvg::resize(const QSizeF& size)
{ {
if (!size.isValid() || size.width() < 1 || size.height() < 1 || size == d->panelSize) { if (!size.isValid() || size.width() < 1 || size.height() < 1 || size == d->panels[d->prefix]->panelSize) {
return; return;
} }
d->panelSize = size; d->panels[d->prefix]->panelSize = size;
d->updateSizes(); d->updateSizes();
} }
@ -183,79 +218,104 @@ void PanelSvg::resize(qreal width, qreal height)
qreal PanelSvg::marginSize(const Plasma::MarginEdge edge) const qreal PanelSvg::marginSize(const Plasma::MarginEdge edge) const
{ {
if (d->noBorderPadding) { if (d->panels[d->prefix]->noBorderPadding) {
return .0; return .0;
} }
switch (edge) { switch (edge) {
case Plasma::TopMargin: case Plasma::TopMargin:
return d->topHeight; return d->panels[d->prefix]->topHeight;
break; break;
case Plasma::LeftMargin: case Plasma::LeftMargin:
return d->leftWidth; return d->panels[d->prefix]->leftWidth;
break; break;
case Plasma::RightMargin: case Plasma::RightMargin:
return d->rightWidth; return d->panels[d->prefix]->rightWidth;
break; break;
//Plasma::BottomMargin //Plasma::BottomMargin
default: default:
return d->bottomHeight; return d->panels[d->prefix]->bottomHeight;
break; break;
} }
} }
QBitmap PanelSvg::mask() const QBitmap PanelSvg::mask() const
{ {
if (!d->cachedBackground) { if (!d->panels[d->prefix]->cachedBackground) {
d->generateBackground(); d->generateBackground();
} }
return d->cachedBackground->alphaChannel().createMaskFromColor(Qt::black); return d->panels[d->prefix]->cachedBackground->alphaChannel().createMaskFromColor(Qt::black);
}
void PanelSvg::setCacheAllRenderedPanels(bool cache)
{
if (d->cacheAll && !cache) {
clearCache();
}
d->cacheAll = cache;
}
bool PanelSvg::cacheAllRenderedPanels() const
{
return d->cacheAll;
}
void PanelSvg::clearCache()
{
qDeleteAll(d->panels);
if (!d->panels.contains(d->prefix)) {
d->panels.insert(d->prefix, new PanelData());
}
} }
void PanelSvg::paint(QPainter* painter, const QRectF& rect, const QPointF& pos) void PanelSvg::paint(QPainter* painter, const QRectF& rect, const QPointF& pos)
{ {
if (!d->cachedBackground) { if (!d->panels[d->prefix]->cachedBackground) {
d->generateBackground(); d->generateBackground();
} }
//FIXME: this is redundant with generatebackground for now //FIXME: this is redundant with generatebackground for now
bool origined = d->contentAtOrigin; bool origined = d->panels[d->prefix]->contentAtOrigin;
const int topOffset = origined ? 0 - d->topHeight : 0; const int topOffset = origined ? 0 - d->panels[d->prefix]->topHeight : 0;
const int leftOffset = origined ? 0 - d->leftWidth : 0; const int leftOffset = origined ? 0 - d->panels[d->prefix]->leftWidth : 0;
painter->drawPixmap(rect, *d->cachedBackground, rect.translated(-pos.x()-leftOffset,-pos.y()-topOffset)); painter->drawPixmap(rect, *d->panels[d->prefix]->cachedBackground, rect.translated(-pos.x()-leftOffset,-pos.y()-topOffset));
} }
void PanelSvg::Private::generateBackground() void PanelSvg::Private::generateBackground()
{ {
bool origined = contentAtOrigin; PanelData *panel = panels[prefix];
bool origined = panel->contentAtOrigin;
const int topWidth = background->elementSize(prefix + "top").width(); const int topWidth = background->elementSize(prefix + "top").width();
const int leftHeight = background->elementSize(prefix + "left").height(); const int leftHeight = background->elementSize(prefix + "left").height();
const int topOffset = origined ? 0 - topHeight : 0; const int topOffset = origined ? 0 - panel->topHeight : 0;
const int leftOffset = origined ? 0 - leftWidth : 0; const int leftOffset = origined ? 0 - panel->leftWidth : 0;
if (!cachedBackground) { if (!panel->cachedBackground) {
const int contentWidth = panelSize.width() - leftWidth - rightWidth; const int contentWidth = panel->panelSize.width() - panel->leftWidth - panel->rightWidth;
const int contentHeight = panelSize.height() - topHeight - bottomHeight; const int contentHeight = panel->panelSize.height() - panel->topHeight - panel->bottomHeight;
int contentTop = 0; int contentTop = 0;
int contentLeft = 0; int contentLeft = 0;
int rightOffset = contentWidth; int rightOffset = contentWidth;
int bottomOffset = contentHeight; int bottomOffset = contentHeight;
delete cachedBackground; delete panel->cachedBackground;
cachedBackground = new QPixmap(leftWidth + contentWidth + rightWidth, panel->cachedBackground = new QPixmap(panel->leftWidth + contentWidth + panel->rightWidth,
topHeight + contentHeight + bottomHeight); panel->topHeight + contentHeight + panel->bottomHeight);
cachedBackground->fill(Qt::transparent); panel->cachedBackground->fill(Qt::transparent);
QPainter p(cachedBackground); QPainter p(panel->cachedBackground);
p.setCompositionMode(QPainter::CompositionMode_Source); p.setCompositionMode(QPainter::CompositionMode_Source);
p.setRenderHint(QPainter::SmoothPixmapTransform); p.setRenderHint(QPainter::SmoothPixmapTransform);
if (origined) { if (origined) {
p.translate(leftWidth, topHeight); p.translate(panel->leftWidth, panel->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. //FIXME: This is a hack to fix a drawing problems with svg files where a thin transparent border is drawn around the svg image.
@ -264,7 +324,7 @@ void PanelSvg::Private::generateBackground()
//CENTER //CENTER
if (tileCenter) { if (panel->tileCenter) {
if (contentHeight > 0 && contentWidth > 0) { if (contentHeight > 0 && contentWidth > 0) {
int centerTileHeight; int centerTileHeight;
int centerTileWidth; int centerTileWidth;
@ -279,21 +339,21 @@ void PanelSvg::Private::generateBackground()
background->paint(&centerPainter, QPoint(0, 0), prefix + "center"); background->paint(&centerPainter, QPoint(0, 0), prefix + "center");
} }
p.drawTiledPixmap(QRect(contentLeft - leftWidth, contentTop - topHeight, p.drawTiledPixmap(QRect(contentLeft - panel->leftWidth, contentTop - panel->topHeight,
contentWidth + leftWidth*2, contentHeight + topHeight*2), center); contentWidth + panel->leftWidth*2, contentHeight + panel->topHeight*2), center);
} }
} else { } else {
if (contentHeight > 0 && contentWidth > 0) { if (contentHeight > 0 && contentWidth > 0) {
QSizeF scaledSize = QSizeF(panelSize.width() - QSizeF scaledSize = QSizeF(panel->panelSize.width() -
(leftWidth + rightWidth) + (panel->leftWidth + panel->rightWidth) +
panelSize.width()*(((qreal)(leftWidth + rightWidth)) / panelSize.width()), panel->panelSize.width()*(((qreal)(panel->leftWidth + panel->rightWidth)) / panel->panelSize.width()),
panelSize.height() - panel->panelSize.height() -
(topHeight + bottomHeight) + (panel->topHeight + panel->bottomHeight) +
panelSize.height()*(((qreal)(topHeight + bottomHeight)) / panelSize.height())); panel->panelSize.height()*(((qreal)(panel->topHeight + panel->bottomHeight)) / panel->panelSize.height()));
background->resize(scaledSize.width(), scaledSize.height()); background->resize(scaledSize.width(), scaledSize.height());
background->paint(&p, QRect(contentLeft - leftWidth, contentTop - topHeight, background->paint(&p, QRect(contentLeft - panel->leftWidth, contentTop - panel->topHeight,
contentWidth + leftWidth*2, contentHeight + topHeight*2), contentWidth + panel->leftWidth*2, contentHeight + panel->topHeight*2),
prefix + "center"); prefix + "center");
background->resize(); background->resize();
} }
@ -301,61 +361,61 @@ void PanelSvg::Private::generateBackground()
// Corners // Corners
if (enabledBorders & TopBorder) { if (panel->enabledBorders & TopBorder) {
if (!origined) { if (!origined) {
contentTop = topHeight; contentTop = panel->topHeight;
bottomOffset += topHeight; bottomOffset += panel->topHeight;
} }
if (enabledBorders & LeftBorder) { if (panel->enabledBorders & LeftBorder) {
background->paint(&p, QRect(leftOffset, topOffset, leftWidth, topHeight), prefix + "topleft"); background->paint(&p, QRect(leftOffset, topOffset, panel->leftWidth, panel->topHeight), prefix + "topleft");
if (!origined) { if (!origined) {
contentLeft = leftWidth; contentLeft = panel->leftWidth;
rightOffset = contentWidth + leftWidth; rightOffset = contentWidth + panel->leftWidth;
} }
} }
if (enabledBorders & RightBorder) { if (panel->enabledBorders & RightBorder) {
background->paint(&p, QRect(rightOffset, topOffset, rightWidth, topHeight), prefix + "topright"); background->paint(&p, QRect(rightOffset, topOffset, panel->rightWidth, panel->topHeight), prefix + "topright");
} }
} }
if (enabledBorders & BottomBorder) { if (panel->enabledBorders & BottomBorder) {
if (enabledBorders & LeftBorder) { if (panel->enabledBorders & LeftBorder) {
background->paint(&p, QRect(leftOffset, bottomOffset, leftWidth, bottomHeight), prefix + "bottomleft"); background->paint(&p, QRect(leftOffset, bottomOffset, panel->leftWidth, panel->bottomHeight), prefix + "bottomleft");
if (!origined) { if (!origined) {
contentLeft = leftWidth; contentLeft = panel->leftWidth;
rightOffset = contentWidth + leftWidth; rightOffset = contentWidth + panel->leftWidth;
} }
} }
if (enabledBorders & RightBorder) { if (panel->enabledBorders & RightBorder) {
background->paint(&p, QRect(rightOffset, bottomOffset, rightWidth, bottomHeight), prefix + "bottomright"); background->paint(&p, QRect(rightOffset, bottomOffset, panel->rightWidth, panel->bottomHeight), prefix + "bottomright");
} }
} }
// Sides // Sides
if (stretchBorders) { if (panel->stretchBorders) {
if (enabledBorders & LeftBorder) { if (panel->enabledBorders & LeftBorder) {
background->paint(&p, QRect(leftOffset, contentTop, leftWidth, contentHeight), prefix + "left"); background->paint(&p, QRect(leftOffset, contentTop, panel->leftWidth, contentHeight), prefix + "left");
} }
if (enabledBorders & RightBorder) { if (panel->enabledBorders & RightBorder) {
background->paint(&p, QRect(rightOffset, contentTop, rightWidth, contentHeight), prefix + "right"); background->paint(&p, QRect(rightOffset, contentTop, panel->rightWidth, contentHeight), prefix + "right");
} }
if (enabledBorders & TopBorder) { if (panel->enabledBorders & TopBorder) {
background->paint(&p, QRect(contentLeft, topOffset, contentWidth, topHeight), prefix + "top"); background->paint(&p, QRect(contentLeft, topOffset, contentWidth, panel->topHeight), prefix + "top");
} }
if (enabledBorders & BottomBorder) { if (panel->enabledBorders & BottomBorder) {
background->paint(&p, QRect(contentLeft, bottomOffset, contentWidth, bottomHeight), prefix + "bottom"); background->paint(&p, QRect(contentLeft, bottomOffset, contentWidth, panel->bottomHeight), prefix + "bottom");
} }
} else { } else {
if (enabledBorders & LeftBorder) { if (panel->enabledBorders & LeftBorder) {
QPixmap left(leftWidth, leftHeight); QPixmap left(panel->leftWidth, leftHeight);
left.fill(Qt::transparent); left.fill(Qt::transparent);
{ {
@ -364,11 +424,11 @@ void PanelSvg::Private::generateBackground()
background->paint(&sidePainter, QPoint(0, 0), prefix + "left"); background->paint(&sidePainter, QPoint(0, 0), prefix + "left");
} }
p.drawTiledPixmap(QRect(leftOffset, contentTop, leftWidth, contentHeight), left); p.drawTiledPixmap(QRect(leftOffset, contentTop, panel->leftWidth, contentHeight), left);
} }
if (enabledBorders & RightBorder) { if (panel->enabledBorders & RightBorder) {
QPixmap right(rightWidth, leftHeight); QPixmap right(panel->rightWidth, leftHeight);
right.fill(Qt::transparent); right.fill(Qt::transparent);
{ {
@ -377,11 +437,11 @@ void PanelSvg::Private::generateBackground()
background->paint(&sidePainter, QPoint(0, 0), prefix + "right"); background->paint(&sidePainter, QPoint(0, 0), prefix + "right");
} }
p.drawTiledPixmap(QRect(rightOffset, contentTop, rightWidth, contentHeight), right); p.drawTiledPixmap(QRect(rightOffset, contentTop, panel->rightWidth, contentHeight), right);
} }
if (enabledBorders & TopBorder) { if (panel->enabledBorders & TopBorder) {
QPixmap top(topWidth, topHeight); QPixmap top(topWidth, panel->topHeight);
top.fill(Qt::transparent); top.fill(Qt::transparent);
{ {
@ -390,11 +450,11 @@ void PanelSvg::Private::generateBackground()
background->paint(&sidePainter, QPoint(0, 0), prefix + "top"); background->paint(&sidePainter, QPoint(0, 0), prefix + "top");
} }
p.drawTiledPixmap(QRect(contentLeft, topOffset, contentWidth, topHeight), top); p.drawTiledPixmap(QRect(contentLeft, topOffset, contentWidth, panel->topHeight), top);
} }
if (enabledBorders & BottomBorder) { if (panel->enabledBorders & BottomBorder) {
QPixmap bottom(topWidth, bottomHeight); QPixmap bottom(topWidth, panel->bottomHeight);
bottom.fill(Qt::transparent); bottom.fill(Qt::transparent);
{ {
@ -403,7 +463,7 @@ void PanelSvg::Private::generateBackground()
background->paint(&sidePainter, QPoint(0, 0), prefix + "bottom"); background->paint(&sidePainter, QPoint(0, 0), prefix + "bottom");
} }
p.drawTiledPixmap(QRect(contentLeft, bottomOffset, contentWidth, bottomHeight), bottom); p.drawTiledPixmap(QRect(contentLeft, bottomOffset, contentWidth, panel->bottomHeight), bottom);
} }
} }
@ -415,38 +475,40 @@ void PanelSvg::Private::generateBackground()
void PanelSvg::Private::updateSizes() void PanelSvg::Private::updateSizes()
{ {
delete cachedBackground; PanelData *panel = panels[prefix];
cachedBackground = 0;
delete panel->cachedBackground;
panel->cachedBackground = 0;
background->resize(); background->resize();
if (enabledBorders & TopBorder) { if (panel->enabledBorders & TopBorder) {
topHeight = background->elementSize(prefix + "top").height(); panel->topHeight = background->elementSize(prefix + "top").height();
} else { } else {
topHeight = 0; panel->topHeight = 0;
} }
if (enabledBorders & LeftBorder) { if (panel->enabledBorders & LeftBorder) {
leftWidth = background->elementSize(prefix + "left").width(); panel->leftWidth = background->elementSize(prefix + "left").width();
} else { } else {
leftWidth = 0; panel->leftWidth = 0;
} }
if (enabledBorders & RightBorder) { if (panel->enabledBorders & RightBorder) {
rightWidth = background->elementSize(prefix + "right").width(); panel->rightWidth = background->elementSize(prefix + "right").width();
} else { } else {
rightWidth = 0; panel->rightWidth = 0;
} }
if (enabledBorders & BottomBorder) { if (panel->enabledBorders & BottomBorder) {
bottomHeight = background->elementSize(prefix + "bottom").height(); panel->bottomHeight = background->elementSize(prefix + "bottom").height();
} else { } else {
bottomHeight = 0; panel->bottomHeight = 0;
} }
//since it's rectangular, topWidth and bottomWidth must be the same //since it's rectangular, topWidth and bottomWidth must be the same
tileCenter = background->hasElement("hint-tile-center"); panel->tileCenter = background->hasElement("hint-tile-center");
noBorderPadding = background->hasElement("hint-no-border-padding"); panel->noBorderPadding = background->hasElement("hint-no-border-padding");
stretchBorders = background->hasElement("hint-stretch-borders"); panel->stretchBorders = background->hasElement("hint-stretch-borders");
emit q->repaintNeeded(); emit q->repaintNeeded();
} }

View File

@ -152,6 +152,24 @@ class PLASMA_EXPORT PanelSvg : public Svg
*/ */
QBitmap mask() const; QBitmap mask() const;
/**
* Sets whether saving all the rendered prefixes in a cache or not
* @arg cache if use the cache or not
*/
void setCacheAllRenderedPanels(bool cache);
/**
* @return if all the different prefixes should be kept in a cache when rendered
*/
bool cacheAllRenderedPanels() const;
/**
* Deletes the internal cache freeing memory: use this if you want to switch the rendered
* element and you don't plan to switch back to the previous one for a long time and you
* used setUseCache(true)
*/
void clearCache();
/** /**
* Paints the loaded SVG with the elements that represents the border * Paints the loaded SVG with the elements that represents the border
* @arg painter the QPainter to use * @arg painter the QPainter to use