don't regenerate frames when setting every property

Summary:
give frameSvg the concept of repaintBlocked(), that enables and
disables the regeneration of the frame data when a property is set.
the use case is when often, a lot of properties are set one after
the other (such as prefix, enabled borders, size)
collapse the formely similar, but a bit different logic of frame
regeneration is a single function for better maintanability.
QML FrameSvgItem sets repaintblocked when it starts and releases it just on oncomponentCompleted

Test Plan:
plasmashell still starts, autotests still work, all frames are rendered correctly
the destruction of old frames is cutted by 50%. in the qml profiler
the creation time of a framesvgitem slightly improved, on this machine from around 26 msecs to around 21, can still be improved, but at least the code is a bit simpler

Reviewers: #plasma

Subscribers: davidedmundson, plasma-devel, #frameworks

Tags: #plasma, #frameworks

Differential Revision: https://phabricator.kde.org/D4414
This commit is contained in:
Marco Martin 2017-02-07 13:05:57 +01:00
parent 50699af19a
commit d8a1a9eb08
8 changed files with 296 additions and 329 deletions

Binary file not shown.

View File

@ -54,6 +54,23 @@ void FrameSvgTest::contentsRect()
QCOMPARE(m_frameSvg->contentsRect(), QRectF(26, 26, 48, 48)); QCOMPARE(m_frameSvg->contentsRect(), QRectF(26, 26, 48, 48));
} }
void FrameSvgTest::repaintBlocked()
{
//check the properties to be correct even if set during a repaint blocked transaction
m_frameSvg->setRepaintBlocked(true);
QVERIFY(m_frameSvg->isRepaintBlocked());
m_frameSvg->setElementPrefix("prefix");
m_frameSvg->setEnabledBorders(Plasma::FrameSvg::TopBorder|Plasma::FrameSvg::LeftBorder);
m_frameSvg->resizeFrame(QSizeF(100,100));
m_frameSvg->setRepaintBlocked(false);
QCOMPARE(m_frameSvg->prefix(), QString("prefix"));
QCOMPARE(m_frameSvg->enabledBorders(), Plasma::FrameSvg::TopBorder|Plasma::FrameSvg::LeftBorder);
QCOMPARE(m_frameSvg->frameSize(), QSizeF(100,100));
}
void FrameSvgTest::setTheme() void FrameSvgTest::setTheme()
{ {
// Should not crash // Should not crash

View File

@ -38,6 +38,7 @@ private Q_SLOTS:
void margins(); void margins();
void contentsRect(); void contentsRect();
void setTheme(); void setTheme();
void repaintBlocked();
private: private:
Plasma::FrameSvg *m_frameSvg; Plasma::FrameSvg *m_frameSvg;

View File

@ -516,10 +516,17 @@ QSGNode *FrameSvgItem::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaint
return oldNode; return oldNode;
} }
void FrameSvgItem::classBegin()
{
QQuickItem::classBegin();
m_frameSvg->setRepaintBlocked(true);
}
void FrameSvgItem::componentComplete() void FrameSvgItem::componentComplete()
{ {
QQuickItem::componentComplete(); QQuickItem::componentComplete();
m_frameSvg->resizeFrame(QSize(width(), height())); m_frameSvg->resizeFrame(QSize(width(), height()));
m_frameSvg->setRepaintBlocked(false);
m_textureChanged = true; m_textureChanged = true;
} }

View File

@ -22,6 +22,7 @@
#define FRAMESVGITEM_P #define FRAMESVGITEM_P
#include <QQuickItem> #include <QQuickItem>
#include <QQmlParserStatus>
#include <Plasma/FrameSvg> #include <Plasma/FrameSvg>
@ -107,6 +108,7 @@ private:
class FrameSvgItem : public QQuickItem class FrameSvgItem : public QQuickItem
{ {
Q_OBJECT Q_OBJECT
Q_INTERFACES(QQmlParserStatus)
/** /**
* Theme relative path of the svg, like "widgets/background" * Theme relative path of the svg, like "widgets/background"
@ -213,6 +215,7 @@ public:
protected: protected:
void classBegin() Q_DECL_OVERRIDE;
void componentComplete() Q_DECL_OVERRIDE; void componentComplete() Q_DECL_OVERRIDE;
/// @endcond /// @endcond

View File

@ -49,7 +49,9 @@ static const int MAX_FRAME_SIZE = 100000;
FrameData::~FrameData() FrameData::~FrameData()
{ {
for (auto it = references.constBegin(), end = references.constEnd(); it != end; ++it) { for (auto it = references.constBegin(), end = references.constEnd(); it != end; ++it) {
it.key()->d->frames.remove(prefix); if (it.key()->d->frame == this) {
it.key()->d->frame = nullptr;
}
} }
} }
@ -59,7 +61,7 @@ FrameSvg::FrameSvg(QObject *parent)
d(new FrameSvgPrivate(this)) d(new FrameSvgPrivate(this))
{ {
connect(this, SIGNAL(repaintNeeded()), this, SLOT(updateNeeded())); connect(this, SIGNAL(repaintNeeded()), this, SLOT(updateNeeded()));
d->frames.insert(QString(), new FrameData(this, QString())); d->frame = new FrameData(this, QString());
} }
FrameSvg::~FrameSvg() FrameSvg::~FrameSvg()
@ -76,7 +78,7 @@ void FrameSvg::setImagePath(const QString &path)
bool updateNeeded = true; bool updateNeeded = true;
clearCache(); clearCache();
FrameData *fd = d->frames[d->prefix]; FrameData *fd = d->frame;
if (fd->refcount() == 1) { if (fd->refcount() == 1) {
// we're the only user of it, let's remove it from the shared keys // we're the only user of it, let's remove it from the shared keys
// we don't want to deref it, however, as we'll still be using it // we don't want to deref it, however, as we'll still be using it
@ -92,7 +94,7 @@ void FrameSvg::setImagePath(const QString &path)
if (!fd) { if (!fd) {
// we need to replace our frame, start by looking in the frame cache // we need to replace our frame, start by looking in the frame cache
FrameData *oldFd = d->frames[d->prefix]; FrameData *oldFd = d->frame;
const QString key = d->cacheId(oldFd, d->prefix); const QString key = d->cacheId(oldFd, d->prefix);
fd = FrameSvgPrivate::s_sharedFrames[theme()->d].value(key); fd = FrameSvgPrivate::s_sharedFrames[theme()->d].value(key);
@ -108,7 +110,7 @@ void FrameSvg::setImagePath(const QString &path)
fd = new FrameData(*oldFd, this); fd = new FrameData(*oldFd, this);
} }
d->frames.insert(d->prefix, fd); d->frame = fd;
} }
setContainsMultipleImages(true); setContainsMultipleImages(true);
@ -127,67 +129,20 @@ void FrameSvg::setImagePath(const QString &path)
void FrameSvg::setEnabledBorders(const EnabledBorders borders) void FrameSvg::setEnabledBorders(const EnabledBorders borders)
{ {
if (borders == d->frames[d->prefix]->enabledBorders) { if (borders == d->enabledBorders) {
return; return;
} }
FrameData *fd = d->frames[d->prefix]; d->enabledBorders = borders;
const QString oldKey = d->cacheId(fd, d->prefix); if (!d->repaintBlocked) {
const EnabledBorders oldBorders = fd->enabledBorders; d->updateFrameData();
fd->enabledBorders = borders;
const QString newKey = d->cacheId(fd, d->prefix);
fd->enabledBorders = oldBorders;
//qCDebug(LOG_PLASMA) << "looking for" << newKey;
FrameData *newFd = FrameSvgPrivate::s_sharedFrames[theme()->d].value(newKey);
if (newFd) {
//qCDebug(LOG_PLASMA) << "FOUND IT!" << newFd->refcount;
// we've found a math, so insert that new one and ref it ..
newFd->ref(this);
d->frames.insert(d->prefix, newFd);
//.. then deref the old one and if it's no longer used, get rid of it
if (fd->deref(this)) {
//const QString oldKey = d->cacheId(fd, d->prefix);
//qCDebug(LOG_PLASMA) << "1. Removing it" << oldKey << fd->refcount;
FrameSvgPrivate::s_sharedFrames[fd->theme].remove(oldKey);
delete fd;
} }
return;
}
if (fd->refcount() == 1) {
// we're the only user of it, let's remove it from the shared keys
// we don't want to deref it, however, as we'll still be using it
FrameSvgPrivate::s_sharedFrames[fd->theme].remove(oldKey);
} else {
// others are using it, but we wish to change its size. so deref it,
// then create a copy of it (we're automatically ref'd via the ctor),
// then insert it into our frames.
fd->deref(this);
fd = new FrameData(*fd, this);
d->frames.insert(d->prefix, fd);
}
fd->enabledBorders = borders;
d->updateAndSignalSizes();
} }
FrameSvg::EnabledBorders FrameSvg::enabledBorders() const FrameSvg::EnabledBorders FrameSvg::enabledBorders() const
{ {
if (d->frames.isEmpty()) { return d->enabledBorders;
return NoBorder;
}
QHash<QString, FrameData *>::const_iterator it = d->frames.constFind(d->prefix);
if (it != d->frames.constEnd()) {
return it.value()->enabledBorders;
} else {
return NoBorder;
}
} }
void FrameSvg::setElementPrefix(Plasma::Types::Location location) void FrameSvg::setElementPrefix(Plasma::Types::Location location)
@ -215,8 +170,6 @@ void FrameSvg::setElementPrefix(Plasma::Types::Location location)
void FrameSvg::setElementPrefix(const QString &prefix) void FrameSvg::setElementPrefix(const QString &prefix)
{ {
const QString oldPrefix(d->prefix);
if (!hasElement(prefix % QLatin1String("-center"))) { if (!hasElement(prefix % QLatin1String("-center"))) {
d->prefix.clear(); d->prefix.clear();
} else { } else {
@ -227,64 +180,11 @@ void FrameSvg::setElementPrefix(const QString &prefix)
} }
d->requestedPrefix = prefix; d->requestedPrefix = prefix;
FrameData *oldFrameData = d->frames.value(oldPrefix);
if (oldPrefix == d->prefix && oldFrameData) {
return;
}
if (!d->frames.contains(d->prefix)) {
if (oldFrameData) {
FrameData *newFd = 0;
if (!oldFrameData->frameSize.isEmpty()) {
const QString key = d->cacheId(oldFrameData, d->prefix);
newFd = FrameSvgPrivate::s_sharedFrames[theme()->d].value(key);
if (newFd && newFd->devicePixelRatio != devicePixelRatio()) {
newFd = 0;
}
}
// we need to put this in the cache if we didn't find it in the shared frames
// and we have a size; if we don't have a size, we'll catch it later
const bool cache = !newFd && !oldFrameData->frameSize.isEmpty();
if (newFd) {
newFd->ref(this);
} else {
newFd = new FrameData(*oldFrameData, this);
}
d->frames.insert(d->prefix, newFd);
if (cache) {
// we have to cache after inserting the frame since the cacheId requires the
// frame to be in the frames collection already
const QString key = d->cacheId(oldFrameData, d->prefix);
//qCDebug(LOG_PLASMA) << this << " 1. inserting as" << key;
FrameSvgPrivate::s_sharedFrames[theme()->d].insert(key, newFd);
newFd->theme = theme()->d;
}
} else {
// couldn't find anything useful, so we just create something here
// we don't have a size for it yet, so don't bother trying to share it just yet
FrameData *newFd = new FrameData(this, d->prefix);
d->frames.insert(d->prefix, newFd);
}
d->updateSizes();
}
if (!d->cacheAll) {
d->frames.remove(oldPrefix);
if (oldFrameData) {
if (oldFrameData->deref(this)) {
const QString oldKey = d->cacheId(oldFrameData, oldPrefix);
FrameSvgPrivate::s_sharedFrames[oldFrameData->theme].remove(oldKey);
delete oldFrameData;
}
}
}
d->location = Types::Floating; d->location = Types::Floating;
if (!d->repaintBlocked) {
d->updateFrameData();
}
} }
bool FrameSvg::hasElementPrefix(const QString &prefix) const bool FrameSvg::hasElementPrefix(const QString &prefix) const
@ -337,155 +237,108 @@ void FrameSvg::resizeFrame(const QSizeF &size)
return; return;
} }
FrameData *fd = d->frames[d->prefix]; if (size.toSize() == d->frame->frameSize) {
if (size == fd->frameSize) {
return; return;
} }
d->pendingFrameSize = size.toSize();
const QString oldKey = d->cacheId(fd, d->prefix); if (!d->repaintBlocked) {
const QSize currentSize = fd->frameSize; d->updateFrameData();
fd->frameSize = size.toSize();
const QString newKey = d->cacheId(fd, d->prefix);
fd->frameSize = currentSize;
//qCDebug(LOG_PLASMA) << "looking for" << newKey;
FrameData *newFd = FrameSvgPrivate::s_sharedFrames[theme()->d].value(newKey);
if (newFd) {
//qCDebug(LOG_PLASMA) << "FOUND IT!" << newFd->refcount;
// we've found a math, so insert that new one and ref it ..
newFd->ref(this);
d->frames.insert(d->prefix, newFd);
//.. then deref the old one and if it's no longer used, get rid of it
if (fd->deref(this)) {
//const QString oldKey = d->cacheId(fd, d->prefix);
//qCDebug(LOG_PLASMA) << "1. Removing it" << oldKey << fd->refcount;
FrameSvgPrivate::s_sharedFrames[fd->theme].remove(oldKey);
delete fd;
} }
return;
}
if (fd->refcount() == 1) {
// we're the only user of it, let's remove it from the shared keys
// we don't want to deref it, however, as we'll still be using it
FrameSvgPrivate::s_sharedFrames[fd->theme].remove(oldKey);
} else {
// others are using it, but we wish to change its size. so deref it,
// then create a copy of it (we're automatically ref'd via the ctor),
// then insert it into our frames.
fd->deref(this);
fd = new FrameData(*fd, this);
d->frames.insert(d->prefix, fd);
}
d->updateSizes();
fd->frameSize = size.toSize();
// we know it isn't in s_sharedFrames due to the check above, so insert it now
FrameSvgPrivate::s_sharedFrames[theme()->d].insert(newKey, fd);
fd->theme = theme()->d;
} }
QSizeF FrameSvg::frameSize() const QSizeF FrameSvg::frameSize() const
{ {
QHash<QString, FrameData *>::const_iterator it = d->frames.constFind(d->prefix); if (!d->frame) {
if (it == d->frames.constEnd()) {
return QSize(-1, -1); return QSize(-1, -1);
} else { } else {
return d->frameSize(it.value()); return d->frameSize(d->frame);
} }
} }
qreal FrameSvg::marginSize(const Plasma::Types::MarginEdge edge) const qreal FrameSvg::marginSize(const Plasma::Types::MarginEdge edge) const
{ {
if (d->frames[d->prefix]->noBorderPadding) { if (d->frame->noBorderPadding) {
return .0; return .0;
} }
switch (edge) { switch (edge) {
case Plasma::Types::TopMargin: case Plasma::Types::TopMargin:
return d->frames[d->prefix]->topMargin; return d->frame->topMargin;
break; break;
case Plasma::Types::LeftMargin: case Plasma::Types::LeftMargin:
return d->frames[d->prefix]->leftMargin; return d->frame->leftMargin;
break; break;
case Plasma::Types::RightMargin: case Plasma::Types::RightMargin:
return d->frames[d->prefix]->rightMargin; return d->frame->rightMargin;
break; break;
//Plasma::BottomMargin //Plasma::BottomMargin
default: default:
return d->frames[d->prefix]->bottomMargin; return d->frame->bottomMargin;
break; break;
} }
} }
qreal FrameSvg::fixedMarginSize(const Plasma::Types::MarginEdge edge) const qreal FrameSvg::fixedMarginSize(const Plasma::Types::MarginEdge edge) const
{ {
if (d->frames[d->prefix]->noBorderPadding) { if (d->frame->noBorderPadding) {
return .0; return .0;
} }
switch (edge) { switch (edge) {
case Plasma::Types::TopMargin: case Plasma::Types::TopMargin:
return d->frames[d->prefix]->fixedTopMargin; return d->frame->fixedTopMargin;
break; break;
case Plasma::Types::LeftMargin: case Plasma::Types::LeftMargin:
return d->frames[d->prefix]->fixedLeftMargin; return d->frame->fixedLeftMargin;
break; break;
case Plasma::Types::RightMargin: case Plasma::Types::RightMargin:
return d->frames[d->prefix]->fixedRightMargin; return d->frame->fixedRightMargin;
break; break;
//Plasma::BottomMargin //Plasma::BottomMargin
default: default:
return d->frames[d->prefix]->fixedBottomMargin; return d->frame->fixedBottomMargin;
break; break;
} }
} }
void FrameSvg::getMargins(qreal &left, qreal &top, qreal &right, qreal &bottom) const void FrameSvg::getMargins(qreal &left, qreal &top, qreal &right, qreal &bottom) const
{ {
FrameData *frame = d->frames[d->prefix]; if (d->frame->noBorderPadding) {
if (frame->noBorderPadding) {
left = top = right = bottom = 0; left = top = right = bottom = 0;
return; return;
} }
top = frame->topMargin; top = d->frame->topMargin;
left = frame->leftMargin; left = d->frame->leftMargin;
right = frame->rightMargin; right = d->frame->rightMargin;
bottom = frame->bottomMargin; bottom = d->frame->bottomMargin;
} }
void FrameSvg::getFixedMargins(qreal &left, qreal &top, qreal &right, qreal &bottom) const void FrameSvg::getFixedMargins(qreal &left, qreal &top, qreal &right, qreal &bottom) const
{ {
FrameData *frame = d->frames[d->prefix]; if (d->frame->noBorderPadding) {
if (frame->noBorderPadding) {
left = top = right = bottom = 0; left = top = right = bottom = 0;
return; return;
} }
top = frame->fixedTopMargin; top = d->frame->fixedTopMargin;
left = frame->fixedLeftMargin; left = d->frame->fixedLeftMargin;
right = frame->fixedRightMargin; right = d->frame->fixedRightMargin;
bottom = frame->fixedBottomMargin; bottom = d->frame->fixedBottomMargin;
} }
QRectF FrameSvg::contentsRect() const QRectF FrameSvg::contentsRect() const
{ {
FrameData* frame = d->frames.value(d->prefix); if (d->frame) {
if (frame) { QRectF rect(QPoint(0,0), d->frame->frameSize);
QRectF rect(QPoint(0,0), frame->frameSize); return rect.adjusted(d->frame->leftMargin, d->frame->topMargin, -d->frame->rightMargin, -d->frame->bottomMargin);
return rect.adjusted(frame->leftMargin, frame->topMargin, -frame->rightMargin, -frame->bottomMargin);
} else { } else {
return QRectF(); return QRectF();
} }
@ -499,16 +352,15 @@ QPixmap FrameSvg::alphaMask() const
QRegion FrameSvg::mask() const QRegion FrameSvg::mask() const
{ {
FrameData *frame = d->frames[d->prefix]; QString id = d->cacheId(d->frame, QString());
QString id = d->cacheId(frame, QString());
QRegion* obj = frame->cachedMasks.object(id); QRegion* obj = d->frame->cachedMasks.object(id);
QRegion result; QRegion result;
if (!obj) { if (!obj) {
obj = new QRegion(QBitmap(d->alphaMask().alphaChannel().createMaskFromColor(Qt::black))); obj = new QRegion(QBitmap(d->alphaMask().alphaChannel().createMaskFromColor(Qt::black)));
result = *obj; result = *obj;
frame->cachedMasks.insert(id, obj); d->frame->cachedMasks.insert(id, obj);
} }
else { else {
result = *obj; result = *obj;
@ -532,59 +384,45 @@ bool FrameSvg::cacheAllRenderedFrames() const
void FrameSvg::clearCache() void FrameSvg::clearCache()
{ {
FrameData *frame = d->frames[d->prefix]; if (d->frame) {
d->frame->cachedBackground = QPixmap();
// delete all the frames that aren't this one
QMutableHashIterator<QString, FrameData *> it(d->frames);
while (it.hasNext()) {
FrameData *p = it.next().value();
if (frame != p) {
//TODO: should we clear from the Theme pixmap cache as well?
if (p->deref(this)) {
const QString key = d->cacheId(p, it.key());
FrameSvgPrivate::s_sharedFrames[p->theme].remove(key);
p->cachedBackground = QPixmap();
}
it.remove();
} }
if (d->maskFrame) {
d->maskFrame->cachedBackground = QPixmap();
} }
} }
QPixmap FrameSvg::framePixmap() QPixmap FrameSvg::framePixmap()
{ {
FrameData *frame = d->frames[d->prefix]; if (d->frame->cachedBackground.isNull()) {
if (frame->cachedBackground.isNull()) { d->generateBackground(d->frame);
d->generateBackground(frame);
} }
return frame->cachedBackground; return d->frame->cachedBackground;
} }
void FrameSvg::paintFrame(QPainter *painter, const QRectF &target, const QRectF &source) void FrameSvg::paintFrame(QPainter *painter, const QRectF &target, const QRectF &source)
{ {
FrameData *frame = d->frames[d->prefix]; if (d->frame->cachedBackground.isNull()) {
if (frame->cachedBackground.isNull()) { d->generateBackground(d->frame);
d->generateBackground(frame); if (d->frame->cachedBackground.isNull()) {
if (frame->cachedBackground.isNull()) {
return; return;
} }
} }
painter->drawPixmap(target, frame->cachedBackground, source.isValid() ? source : target); painter->drawPixmap(target, d->frame->cachedBackground, source.isValid() ? source : target);
} }
void FrameSvg::paintFrame(QPainter *painter, const QPointF &pos) void FrameSvg::paintFrame(QPainter *painter, const QPointF &pos)
{ {
FrameData *frame = d->frames[d->prefix]; if (d->frame->cachedBackground.isNull()) {
if (frame->cachedBackground.isNull()) { d->generateBackground(d->frame);
d->generateBackground(frame); if (d->frame->cachedBackground.isNull()) {
if (frame->cachedBackground.isNull()) {
return; return;
} }
} }
painter->drawPixmap(pos, frame->cachedBackground); painter->drawPixmap(pos, d->frame->cachedBackground);
} }
//#define DEBUG_FRAMESVG_CACHE //#define DEBUG_FRAMESVG_CACHE
@ -596,36 +434,27 @@ FrameSvgPrivate::~FrameSvgPrivate()
#endif #endif
#endif #endif
QHashIterator<QString, FrameData *> it(frames);
while (it.hasNext()) {
it.next();
if (it.value()) {
// we remove all references from this widget to the frame, and delete it if we're the // we remove all references from this widget to the frame, and delete it if we're the
// last user // last user
if (it.value()->removeRefs(q)) { if (frame && frame->removeRefs(q)) {
const QString key = cacheId(it.value(), it.key()); const QString key = cacheId(frame, frame->prefix);
#ifdef DEBUG_FRAMESVG_CACHE #ifdef DEBUG_FRAMESVG_CACHE
#ifndef NDEBUG #ifndef NDEBUG
// qCDebug(LOG_PLASMA) << "2. Removing it" << key << it.value() << it.value()->refcount() << s_sharedFrames[theme()->d].contains(key); // qCDebug(LOG_PLASMA) << "2. Removing it" << key << frame << frame->refcount() << s_sharedFrames[theme()->d].contains(key);
#endif
#endif
s_sharedFrames[it.value()->theme].remove(key);
delete it.value();
}
#ifdef DEBUG_FRAMESVG_CACHE
else {
#ifndef NDEBUG
// qCDebug(LOG_PLASMA) << "still shared:" << cacheId(it.value(), it.key()) << it.value() << it.value()->refcount() << it.value()->isUsed();
#endif
}
} else {
#ifndef NDEBUG
// qCDebug(LOG_PLASMA) << "lost our value for" << it.key();
#endif #endif
#endif #endif
s_sharedFrames[frame->theme].remove(key);
delete frame;
} }
//same thing for maskFrame
if (maskFrame && maskFrame->removeRefs(q)) {
const QString key = cacheId(maskFrame, maskFrame->prefix);
s_sharedFrames[maskFrame->theme].remove(key);
delete maskFrame;
} }
#ifdef DEBUG_FRAMESVG_CACHE #ifdef DEBUG_FRAMESVG_CACHE
QHashIterator<QString, FrameData *> it2(s_sharedFrames[theme()->d]); QHashIterator<QString, FrameData *> it2(s_sharedFrames[theme()->d]);
int shares = 0; int shares = 0;
@ -653,12 +482,12 @@ FrameSvgPrivate::~FrameSvgPrivate()
#endif #endif
#endif #endif
frames.clear(); frame = nullptr;
maskFrame = nullptr;
} }
QPixmap FrameSvgPrivate::alphaMask() QPixmap FrameSvgPrivate::alphaMask()
{ {
FrameData *frame = frames[prefix];
QString maskPrefix; QString maskPrefix;
if (q->hasElement(QLatin1String("mask-") % prefix % QLatin1String("center"))) { if (q->hasElement(QLatin1String("mask-") % prefix % QLatin1String("center"))) {
@ -675,38 +504,38 @@ QPixmap FrameSvgPrivate::alphaMask()
return frame->cachedBackground; return frame->cachedBackground;
} else { } else {
QString oldPrefix = prefix;
// We are setting the prefix only temporary to generate // We are setting the prefix only temporary to generate
// the needed mask image // the needed mask image
prefix = maskPrefix % oldPrefix; const QString maskRequestedPrefix = maskPrefix % requestedPrefix;
maskPrefix = maskPrefix % prefix;
if (!frames.contains(prefix)) { if (!maskFrame) {
const QString key = cacheId(frame, prefix); const QString key = cacheId(frame, maskPrefix);
// see if we can find a suitable candidate in the shared frames // see if we can find a suitable candidate in the shared frames
// if successful, ref and insert, otherwise create a new one // if successful, ref and insert, otherwise create a new one
// and insert that into both the shared frames and our frames. // and insert that into both the shared frames and our frames.
FrameData *maskFrame = s_sharedFrames[q->theme()->d].value(key); maskFrame = s_sharedFrames[q->theme()->d].value(key);
if (maskFrame) { if (maskFrame) {
maskFrame->ref(q); maskFrame->ref(q);
} else { } else {
maskFrame = new FrameData(*frame, q); maskFrame = new FrameData(*frame, q);
s_sharedFrames[q->theme()->d].insert(key, maskFrame); maskFrame->prefix = maskPrefix;
maskFrame->requestedPrefix = maskRequestedPrefix;
maskFrame->theme = q->theme()->d; maskFrame->theme = q->theme()->d;
s_sharedFrames[q->theme()->d].insert(key, maskFrame);
} }
maskFrame->enabledBorders = frame->enabledBorders; maskFrame->enabledBorders = frame->enabledBorders;
frames.insert(prefix, maskFrame); updateSizes(maskFrame);
updateSizes();
} }
FrameData *maskFrame = frames[prefix]; // maskFrame = frame;
maskFrame->enabledBorders = frame->enabledBorders; maskFrame->enabledBorders = frame->enabledBorders;
if (maskFrame->cachedBackground.isNull() || maskFrame->frameSize != frameSize(frame)) { if (maskFrame->cachedBackground.isNull() || maskFrame->frameSize != frameSize(frame)) {
const QString oldKey = cacheId(maskFrame, prefix); const QString oldKey = cacheId(maskFrame, maskPrefix);
maskFrame->frameSize = frameSize(frame).toSize(); maskFrame->frameSize = frameSize(frame).toSize();
const QString newKey = cacheId(maskFrame, prefix); const QString newKey = cacheId(maskFrame, maskPrefix);
if (s_sharedFrames[q->theme()->d].contains(oldKey)) { if (s_sharedFrames[q->theme()->d].contains(oldKey)) {
s_sharedFrames[q->theme()->d].remove(oldKey); s_sharedFrames[q->theme()->d].remove(oldKey);
s_sharedFrames[q->theme()->d].insert(newKey, maskFrame); s_sharedFrames[q->theme()->d].insert(newKey, maskFrame);
@ -715,27 +544,27 @@ QPixmap FrameSvgPrivate::alphaMask()
maskFrame->cachedBackground = QPixmap(); maskFrame->cachedBackground = QPixmap();
generateBackground(maskFrame); generateBackground(maskFrame);
if (maskFrame->cachedBackground.isNull()) { if (maskFrame->cachedBackground.isNull()) {
return QPixmap(); return QPixmap();
} }
} }
prefix = oldPrefix;
return maskFrame->cachedBackground; return maskFrame->cachedBackground;
} }
} }
void FrameSvgPrivate::generateBackground(FrameData *frame) void FrameSvgPrivate::generateBackground(FrameData *frame)
{ {
if (!frame->cachedBackground.isNull() || !q->hasElementPrefix(q->prefix())) { if (!frame->cachedBackground.isNull() || !q->hasElementPrefix(frame->requestedPrefix)) {
return; return;
} }
const QString id = cacheId(frame, prefix); const QString id = cacheId(frame, frame->prefix);
bool frameCached = !frame->cachedBackground.isNull(); bool frameCached = !frame->cachedBackground.isNull();
bool overlayCached = false; bool overlayCached = false;
const bool overlayAvailable = !prefix.startsWith(QLatin1String("mask-")) && q->hasElement(prefix % QLatin1String("overlay")); const bool overlayAvailable = !frame->prefix.startsWith(QLatin1String("mask-")) && q->hasElement(frame->prefix % QLatin1String("overlay"));
QPixmap overlay; QPixmap overlay;
if (q->isUsingRenderingCache()) { if (q->isUsingRenderingCache()) {
frameCached = q->theme()->findInCache(id, frame->cachedBackground) && !frame->cachedBackground.isNull(); frameCached = q->theme()->findInCache(id, frame->cachedBackground) && !frame->cachedBackground.isNull();
@ -753,20 +582,20 @@ void FrameSvgPrivate::generateBackground(FrameData *frame)
QSize overlaySize; QSize overlaySize;
QPoint actualOverlayPos = QPoint(0, 0); QPoint actualOverlayPos = QPoint(0, 0);
if (overlayAvailable && !overlayCached) { if (overlayAvailable && !overlayCached) {
overlaySize = q->elementSize(prefix % QLatin1String("overlay")); overlaySize = q->elementSize(frame->prefix % QLatin1String("overlay"));
if (q->hasElement(prefix % QLatin1String("hint-overlay-pos-right"))) { if (q->hasElement(frame->prefix % QLatin1String("hint-overlay-pos-right"))) {
actualOverlayPos.setX(frame->frameSize.width() - overlaySize.width()); actualOverlayPos.setX(frame->frameSize.width() - overlaySize.width());
} else if (q->hasElement(prefix % QLatin1String("hint-overlay-pos-bottom"))) { } else if (q->hasElement(frame->prefix % QLatin1String("hint-overlay-pos-bottom"))) {
actualOverlayPos.setY(frame->frameSize.height() - overlaySize.height()); actualOverlayPos.setY(frame->frameSize.height() - overlaySize.height());
//Stretched or Tiled? //Stretched or Tiled?
} else if (q->hasElement(prefix % QLatin1String("hint-overlay-stretch"))) { } else if (q->hasElement(frame->prefix % QLatin1String("hint-overlay-stretch"))) {
overlaySize = frameSize(frame).toSize(); overlaySize = frameSize(frame).toSize();
} else { } else {
if (q->hasElement(prefix % QLatin1String("hint-overlay-tile-horizontal"))) { if (q->hasElement(frame->prefix % QLatin1String("hint-overlay-tile-horizontal"))) {
overlaySize.setWidth(frameSize(frame).width()); overlaySize.setWidth(frameSize(frame).width());
} }
if (q->hasElement(prefix % QLatin1String("hint-overlay-tile-vertical"))) { if (q->hasElement(frame->prefix % QLatin1String("hint-overlay-tile-vertical"))) {
overlaySize.setHeight(frameSize(frame).height()); overlaySize.setHeight(frameSize(frame).height());
} }
} }
@ -775,23 +604,23 @@ void FrameSvgPrivate::generateBackground(FrameData *frame)
QPainter overlayPainter(&overlay); QPainter overlayPainter(&overlay);
overlayPainter.setCompositionMode(QPainter::CompositionMode_SourceIn); overlayPainter.setCompositionMode(QPainter::CompositionMode_SourceIn);
//Tiling? //Tiling?
if (q->hasElement(prefix % QLatin1String("hint-overlay-tile-horizontal")) || if (q->hasElement(frame->prefix % QLatin1String("hint-overlay-tile-horizontal")) ||
q->hasElement(prefix % QLatin1String("hint-overlay-tile-vertical"))) { q->hasElement(frame->prefix % QLatin1String("hint-overlay-tile-vertical"))) {
QSize s = q->size(); QSize s = q->size();
q->resize(q->elementSize(prefix % QLatin1String("overlay"))); q->resize(q->elementSize(frame->prefix % QLatin1String("overlay")));
overlayPainter.drawTiledPixmap(QRect(QPoint(0, 0), overlaySize), q->pixmap(prefix % QLatin1String("overlay"))); overlayPainter.drawTiledPixmap(QRect(QPoint(0, 0), overlaySize), q->pixmap(frame->prefix % QLatin1String("overlay")));
q->resize(s); q->resize(s);
} else { } else {
q->paint(&overlayPainter, QRect(actualOverlayPos, overlaySize), prefix % QLatin1String("overlay")); q->paint(&overlayPainter, QRect(actualOverlayPos, overlaySize), frame->prefix % QLatin1String("overlay"));
} }
overlayPainter.end(); overlayPainter.end();
} }
if (!frameCached) { if (!frameCached) {
cacheFrame(prefix, frame->cachedBackground, overlayCached ? overlay : QPixmap()); cacheFrame(frame->prefix, frame->cachedBackground, overlayCached ? overlay : QPixmap());
} }
if (!overlay.isNull()) { if (!overlay.isNull()) {
@ -832,11 +661,11 @@ void FrameSvgPrivate::generateFrameBackground(FrameData *frame)
paintCorner(p, frame, FrameSvg::RightBorder|FrameSvg::BottomBorder, contentRect); paintCorner(p, frame, FrameSvg::RightBorder|FrameSvg::BottomBorder, contentRect);
// Sides // Sides
const int leftHeight = q->elementSize(prefix % QLatin1String("left")).height(); const int leftHeight = q->elementSize(frame->prefix % QLatin1String("left")).height();
paintBorder(p, frame, FrameSvg::LeftBorder, QSize(frame->leftWidth, leftHeight) * q->devicePixelRatio(), contentRect); paintBorder(p, frame, FrameSvg::LeftBorder, QSize(frame->leftWidth, leftHeight) * q->devicePixelRatio(), contentRect);
paintBorder(p, frame, FrameSvg::RightBorder, QSize(frame->rightWidth, leftHeight) * q->devicePixelRatio(), contentRect); paintBorder(p, frame, FrameSvg::RightBorder, QSize(frame->rightWidth, leftHeight) * q->devicePixelRatio(), contentRect);
const int topWidth = q->elementSize(prefix % QLatin1String("top")).width(); const int topWidth = q->elementSize(frame->prefix % QLatin1String("top")).width();
paintBorder(p, frame, FrameSvg::TopBorder, QSize(topWidth, frame->topHeight) * q->devicePixelRatio(), contentRect); paintBorder(p, frame, FrameSvg::TopBorder, QSize(topWidth, frame->topHeight) * q->devicePixelRatio(), contentRect);
paintBorder(p, frame, FrameSvg::BottomBorder, QSize(topWidth, frame->bottomHeight) * q->devicePixelRatio(), contentRect); paintBorder(p, frame, FrameSvg::BottomBorder, QSize(topWidth, frame->bottomHeight) * q->devicePixelRatio(), contentRect);
p.end(); p.end();
@ -849,21 +678,89 @@ QRect FrameSvgPrivate::contentGeometry(FrameData* frame, const QSize& size) cons
const QSize contentSize(size.width() - frame->leftWidth * q->devicePixelRatio() - frame->rightWidth * q->devicePixelRatio(), const QSize contentSize(size.width() - frame->leftWidth * q->devicePixelRatio() - frame->rightWidth * q->devicePixelRatio(),
size.height() - frame->topHeight * q->devicePixelRatio() - frame->bottomHeight * q->devicePixelRatio()); size.height() - frame->topHeight * q->devicePixelRatio() - frame->bottomHeight * q->devicePixelRatio());
QRect contentRect(QPoint(0,0), contentSize); QRect contentRect(QPoint(0,0), contentSize);
if (frame->enabledBorders & FrameSvg::LeftBorder && q->hasElement(prefix % QLatin1String("left"))) { if (frame->enabledBorders & FrameSvg::LeftBorder && q->hasElement(frame->prefix % QLatin1String("left"))) {
contentRect.translate(frame->leftWidth * q->devicePixelRatio(), 0); contentRect.translate(frame->leftWidth * q->devicePixelRatio(), 0);
} }
// Corners // Corners
if (frame->enabledBorders & FrameSvg::TopBorder && q->hasElement(prefix % QLatin1String("top"))) { if (frame->enabledBorders & FrameSvg::TopBorder && q->hasElement(frame->prefix % QLatin1String("top"))) {
contentRect.translate(0, frame->topHeight * q->devicePixelRatio()); contentRect.translate(0, frame->topHeight * q->devicePixelRatio());
} }
return contentRect; return contentRect;
} }
void FrameSvgPrivate::updateFrameData()
{
FrameData *fd = frame;
const QString oldKey = cacheId(fd, fd->prefix);
const FrameSvg::EnabledBorders oldBorders = fd->enabledBorders;
const QSize currentSize = fd->frameSize;
fd->enabledBorders = enabledBorders;
fd->frameSize = pendingFrameSize;
const QString newKey = cacheId(fd, prefix);
//reset frame to old values
fd->enabledBorders = oldBorders;
fd->frameSize = currentSize;
//FIXME: something more efficient than string comparison?
if (oldKey == newKey) {
return;
}
//qCDebug(LOG_PLASMA) << "looking for" << newKey;
FrameData *newFd = FrameSvgPrivate::s_sharedFrames[q->theme()->d].value(newKey);
if (newFd) {
//qCDebug(LOG_PLASMA) << "FOUND IT!" << newFd->refcount;
// we've found a math, so insert that new one and ref it ..
newFd->ref(q);
frame = newFd;
//.. then deref the old one and if it's no longer used, get rid of it
if (fd->deref(q)) {
//const QString oldKey = cacheId(fd, prefix);
//qCDebug(LOG_PLASMA) << "1. Removing it" << oldKey << fd->refcount;
FrameSvgPrivate::s_sharedFrames[fd->theme].remove(oldKey);
delete fd;
}
return;
}
if (fd->refcount() == 1) {
// we're the only user of it, let's remove it from the shared keys
// we don't want to deref it, however, as we'll still be using it
FrameSvgPrivate::s_sharedFrames[fd->theme].remove(oldKey);
} else {
// others are using it, but we wish to change its size. so deref it,
// then create a copy of it (we're automatically ref'd via the ctor),
// then insert it into our frames.
fd->deref(q);
fd = new FrameData(*fd, q);
}
frame = fd;
fd->prefix = prefix;
fd->requestedPrefix = requestedPrefix;
//updateSizes();
fd->enabledBorders = enabledBorders;
fd->frameSize = pendingFrameSize;
// we know it isn't in s_sharedFrames due to the check above, so insert it now
FrameSvgPrivate::s_sharedFrames[q->theme()->d].insert(newKey, fd);
fd->theme = q->theme()->d;
updateAndSignalSizes();
}
void FrameSvgPrivate::paintCenter(QPainter& p, FrameData* frame, const QRect& contentRect, const QSize& fullSize) void FrameSvgPrivate::paintCenter(QPainter& p, FrameData* frame, const QRect& contentRect, const QSize& fullSize)
{ {
if (!contentRect.isEmpty()) { if (!contentRect.isEmpty()) {
const QString centerElementId = prefix % QLatin1String("center"); const QString centerElementId = frame->prefix % QLatin1String("center");
if (frame->tileCenter) { if (frame->tileCenter) {
QSize centerTileSize = q->elementSize(centerElementId); QSize centerTileSize = q->elementSize(centerElementId);
QPixmap center(centerTileSize); QPixmap center(centerTileSize);
@ -897,7 +794,7 @@ void FrameSvgPrivate::paintCenter(QPainter& p, FrameData* frame, const QRect& co
void FrameSvgPrivate::paintBorder(QPainter& p, FrameData* frame, const FrameSvg::EnabledBorders borders, const QSize& size, const QRect& contentRect) const void FrameSvgPrivate::paintBorder(QPainter& p, FrameData* frame, const FrameSvg::EnabledBorders borders, const QSize& size, const QRect& contentRect) const
{ {
QString side = prefix % FrameSvgHelpers::borderToElementId(borders); QString side = frame->prefix % FrameSvgHelpers::borderToElementId(borders);
if (frame->enabledBorders & borders && q->hasElement(side) && !size.isEmpty()) { if (frame->enabledBorders & borders && q->hasElement(side) && !size.isEmpty()) {
if (frame->stretchBorders) { if (frame->stretchBorders) {
q->paint(&p, FrameSvgHelpers::sectionRect(borders, contentRect, frame->frameSize * q->devicePixelRatio()), side); q->paint(&p, FrameSvgHelpers::sectionRect(borders, contentRect, frame->frameSize * q->devicePixelRatio()), side);
@ -916,7 +813,7 @@ void FrameSvgPrivate::paintBorder(QPainter& p, FrameData* frame, const FrameSvg:
void FrameSvgPrivate::paintCorner(QPainter& p, FrameData* frame, Plasma::FrameSvg::EnabledBorders border, const QRect& contentRect) const void FrameSvgPrivate::paintCorner(QPainter& p, FrameData* frame, Plasma::FrameSvg::EnabledBorders border, const QRect& contentRect) const
{ {
QString corner = prefix % FrameSvgHelpers::borderToElementId(border); QString corner = frame->prefix % FrameSvgHelpers::borderToElementId(border);
if (frame->enabledBorders & border && q->hasElement(corner)) { if (frame->enabledBorders & border && q->hasElement(corner)) {
q->paint(&p, FrameSvgHelpers::sectionRect(border, contentRect, frame->frameSize * q->devicePixelRatio()), corner); q->paint(&p, FrameSvgHelpers::sectionRect(border, contentRect, frame->frameSize * q->devicePixelRatio()), corner);
} }
@ -936,8 +833,6 @@ void FrameSvgPrivate::cacheFrame(const QString &prefixToSave, const QPixmap &bac
} }
//insert background //insert background
FrameData *frame = frames.value(prefixToSave);
if (!frame) { if (!frame) {
return; return;
} }
@ -954,10 +849,9 @@ void FrameSvgPrivate::cacheFrame(const QString &prefixToSave, const QPixmap &bac
} }
} }
void FrameSvgPrivate::updateSizes() const void FrameSvgPrivate::updateSizes(FrameData *frame) const
{ {
//qCDebug(LOG_PLASMA) << "!!!!!!!!!!!!!!!!!!!!!! updating sizes" << prefix; //qCDebug(LOG_PLASMA) << "!!!!!!!!!!!!!!!!!!!!!! updating sizes" << prefix;
FrameData *frame = frames[prefix];
Q_ASSERT(frame); Q_ASSERT(frame);
QSize s = q->size(); QSize s = q->size();
@ -965,20 +859,20 @@ void FrameSvgPrivate::updateSizes() const
frame->cachedBackground = QPixmap(); frame->cachedBackground = QPixmap();
//This has the same size regardless the border is enabled or not //This has the same size regardless the border is enabled or not
frame->fixedTopHeight = q->elementSize(prefix % QLatin1String("top")).height(); frame->fixedTopHeight = q->elementSize(frame->prefix % QLatin1String("top")).height();
if (q->hasElement(prefix % QLatin1String("hint-top-margin"))) { if (q->hasElement(frame->prefix % QLatin1String("hint-top-margin"))) {
frame->fixedTopMargin = q->elementSize(prefix % QLatin1String("hint-top-margin")).height(); frame->fixedTopMargin = q->elementSize(frame->prefix % QLatin1String("hint-top-margin")).height();
} else { } else {
frame->fixedTopMargin = frame->fixedTopHeight; frame->fixedTopMargin = frame->fixedTopHeight;
} }
//The same, but its size depends from the margin being enabled //The same, but its size depends from the margin being enabled
if (frame->enabledBorders & FrameSvg::TopBorder) { if (frame->enabledBorders & FrameSvg::TopBorder) {
frame->topHeight = q->elementSize(prefix % QLatin1String("top")).height(); frame->topHeight = q->elementSize(frame->prefix % QLatin1String("top")).height();
if (q->hasElement(prefix % QLatin1String("hint-top-margin"))) { if (q->hasElement(frame->prefix % QLatin1String("hint-top-margin"))) {
frame->topMargin = q->elementSize(prefix % QLatin1String("hint-top-margin")).height(); frame->topMargin = q->elementSize(frame->prefix % QLatin1String("hint-top-margin")).height();
} else { } else {
frame->topMargin = frame->topHeight; frame->topMargin = frame->topHeight;
} }
@ -986,19 +880,19 @@ void FrameSvgPrivate::updateSizes() const
frame->topMargin = frame->topHeight = 0; frame->topMargin = frame->topHeight = 0;
} }
frame->fixedLeftWidth = q->elementSize(prefix % QLatin1String("left")).width(); frame->fixedLeftWidth = q->elementSize(frame->prefix % QLatin1String("left")).width();
if (q->hasElement(prefix % QLatin1String("hint-left-margin"))) { if (q->hasElement(frame->prefix % QLatin1String("hint-left-margin"))) {
frame->fixedLeftMargin = q->elementSize(prefix % QLatin1String("hint-left-margin")).width(); frame->fixedLeftMargin = q->elementSize(frame->prefix % QLatin1String("hint-left-margin")).width();
} else { } else {
frame->fixedLeftMargin = frame->fixedLeftWidth; frame->fixedLeftMargin = frame->fixedLeftWidth;
} }
if (frame->enabledBorders & FrameSvg::LeftBorder) { if (frame->enabledBorders & FrameSvg::LeftBorder) {
frame->leftWidth = q->elementSize(prefix % QLatin1String("left")).width(); frame->leftWidth = q->elementSize(frame->prefix % QLatin1String("left")).width();
if (q->hasElement(prefix % QLatin1String("hint-left-margin"))) { if (q->hasElement(frame->prefix % QLatin1String("hint-left-margin"))) {
frame->leftMargin = q->elementSize(prefix % QLatin1String("hint-left-margin")).width(); frame->leftMargin = q->elementSize(frame->prefix % QLatin1String("hint-left-margin")).width();
} else { } else {
frame->leftMargin = frame->leftWidth; frame->leftMargin = frame->leftWidth;
} }
@ -1006,19 +900,19 @@ void FrameSvgPrivate::updateSizes() const
frame->leftMargin = frame->leftWidth = 0; frame->leftMargin = frame->leftWidth = 0;
} }
frame->fixedRightWidth = q->elementSize(prefix % QLatin1String("right")).width(); frame->fixedRightWidth = q->elementSize(frame->prefix % QLatin1String("right")).width();
if (q->hasElement(prefix % QLatin1String("hint-right-margin"))) { if (q->hasElement(frame->prefix % QLatin1String("hint-right-margin"))) {
frame->fixedRightMargin = q->elementSize(prefix % QLatin1String("hint-right-margin")).width(); frame->fixedRightMargin = q->elementSize(frame->prefix % QLatin1String("hint-right-margin")).width();
} else { } else {
frame->fixedRightMargin = frame->fixedRightWidth; frame->fixedRightMargin = frame->fixedRightWidth;
} }
if (frame->enabledBorders & FrameSvg::RightBorder) { if (frame->enabledBorders & FrameSvg::RightBorder) {
frame->rightWidth = q->elementSize(prefix % QLatin1String("right")).width(); frame->rightWidth = q->elementSize(frame->prefix % QLatin1String("right")).width();
if (q->hasElement(prefix % QLatin1String("hint-right-margin"))) { if (q->hasElement(frame->prefix % QLatin1String("hint-right-margin"))) {
frame->rightMargin = q->elementSize(prefix % QLatin1String("hint-right-margin")).width(); frame->rightMargin = q->elementSize(frame->prefix % QLatin1String("hint-right-margin")).width();
} else { } else {
frame->rightMargin = frame->rightWidth; frame->rightMargin = frame->rightWidth;
} }
@ -1026,19 +920,19 @@ void FrameSvgPrivate::updateSizes() const
frame->rightMargin = frame->rightWidth = 0; frame->rightMargin = frame->rightWidth = 0;
} }
frame->fixedBottomHeight = q->elementSize(prefix % QLatin1String("bottom")).height(); frame->fixedBottomHeight = q->elementSize(frame->prefix % QLatin1String("bottom")).height();
if (q->hasElement(prefix % QLatin1String("hint-bottom-margin"))) { if (q->hasElement(frame->prefix % QLatin1String("hint-bottom-margin"))) {
frame->fixedBottomMargin = q->elementSize(prefix % QLatin1String("hint-bottom-margin")).height(); frame->fixedBottomMargin = q->elementSize(frame->prefix % QLatin1String("hint-bottom-margin")).height();
} else { } else {
frame->fixedBottomMargin = frame->fixedBottomHeight; frame->fixedBottomMargin = frame->fixedBottomHeight;
} }
if (frame->enabledBorders & FrameSvg::BottomBorder) { if (frame->enabledBorders & FrameSvg::BottomBorder) {
frame->bottomHeight = q->elementSize(prefix % QLatin1String("bottom")).height(); frame->bottomHeight = q->elementSize(frame->prefix % QLatin1String("bottom")).height();
if (q->hasElement(prefix % QLatin1String("hint-bottom-margin"))) { if (q->hasElement(frame->prefix % QLatin1String("hint-bottom-margin"))) {
frame->bottomMargin = q->elementSize(prefix % QLatin1String("hint-bottom-margin")).height(); frame->bottomMargin = q->elementSize(frame->prefix % QLatin1String("hint-bottom-margin")).height();
} else { } else {
frame->bottomMargin = frame->bottomHeight; frame->bottomMargin = frame->bottomHeight;
} }
@ -1046,14 +940,14 @@ void FrameSvgPrivate::updateSizes() const
frame->bottomMargin = frame->bottomHeight = 0; frame->bottomMargin = frame->bottomHeight = 0;
} }
frame->composeOverBorder = (q->hasElement(prefix % QLatin1String("hint-compose-over-border")) && frame->composeOverBorder = (q->hasElement(frame->prefix % QLatin1String("hint-compose-over-border")) &&
q->hasElement(QLatin1String("mask-") % prefix % QLatin1String("center"))); q->hasElement(QLatin1String("mask-") % frame->prefix % QLatin1String("center")));
//since it's rectangular, topWidth and bottomWidth must be the same //since it's rectangular, topWidth and bottomWidth must be the same
//the ones that don't have a prefix is for retrocompatibility //the ones that don't have a frame->prefix is for retrocompatibility
frame->tileCenter = (q->hasElement(QStringLiteral("hint-tile-center")) || q->hasElement(prefix % QLatin1String("hint-tile-center"))); frame->tileCenter = (q->hasElement(QStringLiteral("hint-tile-center")) || q->hasElement(frame->prefix % QLatin1String("hint-tile-center")));
frame->noBorderPadding = (q->hasElement(QStringLiteral("hint-no-border-padding")) || q->hasElement(prefix % QLatin1String("hint-no-border-padding"))); frame->noBorderPadding = (q->hasElement(QStringLiteral("hint-no-border-padding")) || q->hasElement(frame->prefix % QLatin1String("hint-no-border-padding")));
frame->stretchBorders = (q->hasElement(QStringLiteral("hint-stretch-borders")) || q->hasElement(prefix % QLatin1String("hint-stretch-borders"))); frame->stretchBorders = (q->hasElement(QStringLiteral("hint-stretch-borders")) || q->hasElement(frame->prefix % QLatin1String("hint-stretch-borders")));
q->resize(s); q->resize(s);
} }
@ -1061,19 +955,19 @@ void FrameSvgPrivate::updateNeeded()
{ {
q->setElementPrefix(requestedPrefix); q->setElementPrefix(requestedPrefix);
q->clearCache(); q->clearCache();
updateSizes(); updateSizes(frame);
} }
void FrameSvgPrivate::updateAndSignalSizes() void FrameSvgPrivate::updateAndSignalSizes()
{ {
updateSizes(); updateSizes(frame);
emit q->repaintNeeded(); emit q->repaintNeeded();
} }
QSizeF FrameSvgPrivate::frameSize(FrameData *frame) const QSizeF FrameSvgPrivate::frameSize(FrameData *frame) const
{ {
if (!frame->frameSize.isValid()) { if (!frame->frameSize.isValid()) {
updateSizes(); updateSizes(frame);
frame->frameSize = q->size(); frame->frameSize = q->size();
} }
@ -1118,6 +1012,20 @@ QString FrameSvg::actualPrefix() const
return d->prefix; return d->prefix;
} }
bool FrameSvg::isRepaintBlocked() const
{
return d->repaintBlocked;
}
void FrameSvg::setRepaintBlocked(bool blocked)
{
d->repaintBlocked = blocked;
if (!blocked) {
d->updateFrameData();
}
}
} // Plasma namespace } // Plasma namespace
#include "moc_framesvg.cpp" #include "moc_framesvg.cpp"

View File

@ -292,11 +292,28 @@ public:
*/ */
QString actualPrefix() const; QString actualPrefix() const;
/**
* @returns true if we are in a transaction of many changes at once
* and we don't want to rebuild the generated graphics for each change yet
* @since 5.31
*/
bool isRepaintBlocked() const;
/**
* If we will do several changes at once in the frame properties,
* such as prefix, enabled borders and size, in order to not regenerate
* the graphics for each change, set this property to true, and set
* it to false again after applying all the changes needed.
* Note that any change will not be visible in the painted frame while this property is set to true.
* @since 5.31
*/
void setRepaintBlocked(bool blocked);
private: private:
FrameSvgPrivate *const d; FrameSvgPrivate *const d;
friend class FrameData; friend class FrameData;
Q_PRIVATE_SLOT(d, void updateSizes()) //Q_PRIVATE_SLOT(d, void updateSizes())
Q_PRIVATE_SLOT(d, void updateNeeded()) Q_PRIVATE_SLOT(d, void updateNeeded())
}; };

View File

@ -88,6 +88,7 @@ public:
int refcount() const; int refcount() const;
QString prefix; QString prefix;
QString requestedPrefix;
FrameSvg::EnabledBorders enabledBorders; FrameSvg::EnabledBorders enabledBorders;
QPixmap cachedBackground; QPixmap cachedBackground;
QCache<QString, QRegion> cachedMasks; QCache<QString, QRegion> cachedMasks;
@ -137,8 +138,12 @@ class FrameSvgPrivate
public: public:
FrameSvgPrivate(FrameSvg *psvg) FrameSvgPrivate(FrameSvg *psvg)
: q(psvg), : q(psvg),
overlayPos(0, 0),
frame(nullptr),
maskFrame(nullptr),
enabledBorders(FrameSvg::AllBorders),
cacheAll(false), cacheAll(false),
overlayPos(0, 0) repaintBlocked(false)
{ {
} }
@ -150,7 +155,7 @@ public:
void generateFrameBackground(FrameData *frame); void generateFrameBackground(FrameData *frame);
QString cacheId(FrameData *frame, const QString &prefixToUse) const; QString cacheId(FrameData *frame, const QString &prefixToUse) const;
void cacheFrame(const QString &prefixToSave, const QPixmap &background, const QPixmap &overlay); void cacheFrame(const QString &prefixToSave, const QPixmap &background, const QPixmap &overlay);
void updateSizes() const; void updateSizes(FrameData *frame) const;
void updateNeeded(); void updateNeeded();
void updateAndSignalSizes(); void updateAndSignalSizes();
QSizeF frameSize(FrameData *frame) const; QSizeF frameSize(FrameData *frame) const;
@ -158,6 +163,7 @@ public:
void paintCorner(QPainter& p, FrameData* frame, Plasma::FrameSvg::EnabledBorders border, const QRect& output) const; void paintCorner(QPainter& p, FrameData* frame, Plasma::FrameSvg::EnabledBorders border, const QRect& output) const;
void paintCenter(QPainter& p, FrameData* frame, const QRect& contentRect, const QSize& fullSize); void paintCenter(QPainter& p, FrameData* frame, const QRect& contentRect, const QSize& fullSize);
QRect contentGeometry(FrameData* frame, const QSize& size) const; QRect contentGeometry(FrameData* frame, const QSize& size) const;
void updateFrameData();
Types::Location location; Types::Location location;
QString prefix; QString prefix;
@ -167,12 +173,20 @@ public:
FrameSvg *q; FrameSvg *q;
bool cacheAll : 1;
QPoint overlayPos; QPoint overlayPos;
QHash<QString, FrameData *> frames; FrameData *frame;
FrameData *maskFrame;
//those can differ from frame->enabledBorders if we are in a transition
FrameSvg::EnabledBorders enabledBorders;
//this can differ from frame->frameSize if we are in a transition
QSize pendingFrameSize;
static QHash<ThemePrivate *, QHash<QString, FrameData *> > s_sharedFrames; static QHash<ThemePrivate *, QHash<QString, FrameData *> > s_sharedFrames;
bool cacheAll : 1;
bool repaintBlocked : 1;
}; };
} }