move setImagePath logic into updateFrameData()
Summary: make sure the framedata creation/destruction is completely in updateFrameData, makes easier to track and possible to use the repaintsblocked logic. now only one framedata instance should be created at startup. CCBUG:376754 Test Plan: * autotests pass, plasma runs ok, crash on 376754 not reproducible anymore * possible to have a plasmashell session start without the creation of a single svg renderer (startups after the first when the cache is generated) * on qml profiler, framesvgitem creation is ~12 msecs the first one created, ~2-300 musecs the subsequent ones, seems to be a bit better than before the whole refactor started * tried against the latest patches that remove the binding loops, still correct rendering and no binding loop * tried with both empty and existing cache in place Reviewers: #plasma, davidedmundson Reviewed By: #plasma, davidedmundson Subscribers: davidedmundson, plasma-devel, #frameworks Tags: #frameworks, #plasma Differential Revision: https://phabricator.kde.org/D4707
This commit is contained in:
parent
af2b27d1b8
commit
2b3e8dfe86
@ -61,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->frame = new FrameData(this, QString());
|
d->frame = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
FrameSvg::~FrameSvg()
|
FrameSvg::~FrameSvg()
|
||||||
@ -75,55 +75,12 @@ void FrameSvg::setImagePath(const QString &path)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool updateNeeded = true;
|
|
||||||
clearCache();
|
clearCache();
|
||||||
|
|
||||||
FrameData *fd = d->frame;
|
|
||||||
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
|
|
||||||
const QString oldKey = d->cacheId(fd, d->prefix);
|
|
||||||
FrameSvgPrivate::s_sharedFrames[fd->theme].remove(oldKey);
|
|
||||||
} else {
|
|
||||||
// others are using this frame, so deref it for ourselves
|
|
||||||
fd->deref(this);
|
|
||||||
fd = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Svg::d->setImagePath(path);
|
|
||||||
|
|
||||||
if (!fd) {
|
|
||||||
// we need to replace our frame, start by looking in the frame cache
|
|
||||||
FrameData *oldFd = d->frame;
|
|
||||||
const QString key = d->cacheId(oldFd, d->prefix);
|
|
||||||
fd = FrameSvgPrivate::s_sharedFrames[theme()->d].value(key);
|
|
||||||
|
|
||||||
if (fd) {
|
|
||||||
// we found one, so ref it and use it; we also don't need to (or want to!)
|
|
||||||
// trigger a full update of the frame since it is already the one we want
|
|
||||||
// and likely already rendered just fine
|
|
||||||
fd->ref(this);
|
|
||||||
updateNeeded = false;
|
|
||||||
} else {
|
|
||||||
// nothing exists for us in the cache, so create a new FrameData based
|
|
||||||
// on the old one
|
|
||||||
fd = new FrameData(*oldFd, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
d->frame = fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
setContainsMultipleImages(true);
|
setContainsMultipleImages(true);
|
||||||
if (updateNeeded) {
|
Svg::d->setImagePath(path);
|
||||||
// ensure our frame is in the cache
|
if (!d->repaintBlocked) {
|
||||||
const QString key = d->cacheId(fd, d->prefix);
|
d->updateFrameData();
|
||||||
FrameSvgPrivate::s_sharedFrames[theme()->d].insert(key, fd);
|
|
||||||
fd->theme = theme()->d;
|
|
||||||
|
|
||||||
// this will emit repaintNeeded() as well when it is done
|
|
||||||
d->updateAndSignalSizes();
|
|
||||||
} else {
|
|
||||||
emit repaintNeeded();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -237,7 +194,7 @@ void FrameSvg::resizeFrame(const QSizeF &size)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (size.toSize() == d->frame->frameSize) {
|
if (d->frame && size.toSize() == d->frame->frameSize) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
d->pendingFrameSize = size.toSize();
|
d->pendingFrameSize = size.toSize();
|
||||||
@ -258,6 +215,10 @@ QSizeF FrameSvg::frameSize() const
|
|||||||
|
|
||||||
qreal FrameSvg::marginSize(const Plasma::Types::MarginEdge edge) const
|
qreal FrameSvg::marginSize(const Plasma::Types::MarginEdge edge) const
|
||||||
{
|
{
|
||||||
|
if (!d->frame) {
|
||||||
|
return .0;
|
||||||
|
}
|
||||||
|
|
||||||
if (d->frame->noBorderPadding) {
|
if (d->frame->noBorderPadding) {
|
||||||
return .0;
|
return .0;
|
||||||
}
|
}
|
||||||
@ -284,6 +245,10 @@ qreal FrameSvg::marginSize(const Plasma::Types::MarginEdge edge) const
|
|||||||
|
|
||||||
qreal FrameSvg::fixedMarginSize(const Plasma::Types::MarginEdge edge) const
|
qreal FrameSvg::fixedMarginSize(const Plasma::Types::MarginEdge edge) const
|
||||||
{
|
{
|
||||||
|
if (!d->frame) {
|
||||||
|
return .0;
|
||||||
|
}
|
||||||
|
|
||||||
if (d->frame->noBorderPadding) {
|
if (d->frame->noBorderPadding) {
|
||||||
return .0;
|
return .0;
|
||||||
}
|
}
|
||||||
@ -523,6 +488,7 @@ QPixmap FrameSvgPrivate::alphaMask()
|
|||||||
maskFrame->prefix = maskPrefix;
|
maskFrame->prefix = maskPrefix;
|
||||||
maskFrame->requestedPrefix = maskRequestedPrefix;
|
maskFrame->requestedPrefix = maskRequestedPrefix;
|
||||||
maskFrame->theme = q->theme()->d;
|
maskFrame->theme = q->theme()->d;
|
||||||
|
maskFrame->imagePath = q->imagePath();
|
||||||
s_sharedFrames[q->theme()->d].insert(key, maskFrame);
|
s_sharedFrames[q->theme()->d].insert(key, maskFrame);
|
||||||
}
|
}
|
||||||
maskFrame->enabledBorders = frame->enabledBorders;
|
maskFrame->enabledBorders = frame->enabledBorders;
|
||||||
@ -692,56 +658,63 @@ QRect FrameSvgPrivate::contentGeometry(FrameData* frame, const QSize& size) cons
|
|||||||
void FrameSvgPrivate::updateFrameData(UpdateType updateType)
|
void FrameSvgPrivate::updateFrameData(UpdateType updateType)
|
||||||
{
|
{
|
||||||
FrameData *fd = frame;
|
FrameData *fd = frame;
|
||||||
|
QString newKey;
|
||||||
|
|
||||||
const QString oldKey = cacheId(fd, fd->prefix);
|
if (fd) {
|
||||||
|
const QString oldKey = cacheId(fd, fd->prefix);
|
||||||
|
|
||||||
const FrameSvg::EnabledBorders oldBorders = fd->enabledBorders;
|
const QString oldPath = fd->imagePath;
|
||||||
const QSize currentSize = fd->frameSize;
|
const FrameSvg::EnabledBorders oldBorders = fd->enabledBorders;
|
||||||
|
const QSize currentSize = fd->frameSize;
|
||||||
|
|
||||||
fd->enabledBorders = enabledBorders;
|
fd->enabledBorders = enabledBorders;
|
||||||
fd->frameSize = pendingFrameSize;
|
fd->frameSize = pendingFrameSize;
|
||||||
|
fd->imagePath = q->imagePath();
|
||||||
|
|
||||||
const QString newKey = cacheId(fd, prefix);
|
newKey = cacheId(fd, prefix);
|
||||||
|
|
||||||
//reset frame to old values
|
//reset frame to old values
|
||||||
fd->enabledBorders = oldBorders;
|
fd->enabledBorders = oldBorders;
|
||||||
fd->frameSize = currentSize;
|
fd->frameSize = currentSize;
|
||||||
|
fd->imagePath = oldPath;
|
||||||
|
|
||||||
//FIXME: something more efficient than string comparison?
|
//FIXME: something more efficient than string comparison?
|
||||||
if (oldKey == newKey) {
|
if (oldKey == newKey) {
|
||||||
return;
|
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;
|
//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;
|
||||||
|
|
||||||
if (fd->refcount() == 1) {
|
//.. then deref the old one and if it's no longer used, get rid of it
|
||||||
// we're the only user of it, let's remove it from the shared keys
|
if (fd->deref(q)) {
|
||||||
// we don't want to deref it, however, as we'll still be using it
|
//const QString oldKey = cacheId(fd, prefix);
|
||||||
FrameSvgPrivate::s_sharedFrames[fd->theme].remove(oldKey);
|
//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);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// others are using it, but we wish to change its size. so deref it,
|
fd = new FrameData(q, QString());
|
||||||
// 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;
|
frame = fd;
|
||||||
@ -750,6 +723,11 @@ void FrameSvgPrivate::updateFrameData(UpdateType updateType)
|
|||||||
//updateSizes();
|
//updateSizes();
|
||||||
fd->enabledBorders = enabledBorders;
|
fd->enabledBorders = enabledBorders;
|
||||||
fd->frameSize = pendingFrameSize;
|
fd->frameSize = pendingFrameSize;
|
||||||
|
fd->imagePath = q->imagePath();
|
||||||
|
//was fd just created empty now?
|
||||||
|
if (newKey.isEmpty()) {
|
||||||
|
newKey = cacheId(fd, prefix);
|
||||||
|
}
|
||||||
|
|
||||||
// we know it isn't in s_sharedFrames due to the check above, so insert it now
|
// 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);
|
FrameSvgPrivate::s_sharedFrames[q->theme()->d].insert(newKey, fd);
|
||||||
@ -827,7 +805,7 @@ QString FrameSvgPrivate::cacheId(FrameData *frame, const QString &prefixToSave)
|
|||||||
{
|
{
|
||||||
const QSize size = frameSize(frame).toSize();
|
const QSize size = frameSize(frame).toSize();
|
||||||
const QLatin1Char s('_');
|
const QLatin1Char s('_');
|
||||||
return QString::number(frame->enabledBorders) % s % QString::number(size.width()) % s % QString::number(size.height()) % s % QString::number(q->scaleFactor()) % s % QString::number(q->devicePixelRatio()) % s % prefixToSave % s % q->imagePath();
|
return QString::number(frame->enabledBorders) % s % QString::number(size.width()) % s % QString::number(size.height()) % s % QString::number(q->scaleFactor()) % s % QString::number(q->devicePixelRatio()) % s % prefixToSave % s % frame->imagePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FrameSvgPrivate::cacheFrame(const QString &prefixToSave, const QPixmap &background, const QPixmap &overlay)
|
void FrameSvgPrivate::cacheFrame(const QString &prefixToSave, const QPixmap &background, const QPixmap &overlay)
|
||||||
@ -958,18 +936,30 @@ void FrameSvgPrivate::updateSizes(FrameData *frame) const
|
|||||||
void FrameSvgPrivate::updateNeeded()
|
void FrameSvgPrivate::updateNeeded()
|
||||||
{
|
{
|
||||||
q->setElementPrefix(requestedPrefix);
|
q->setElementPrefix(requestedPrefix);
|
||||||
|
//frame not created yet?
|
||||||
|
if (!frame) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
q->clearCache();
|
q->clearCache();
|
||||||
updateSizes(frame);
|
updateSizes(frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FrameSvgPrivate::updateAndSignalSizes()
|
void FrameSvgPrivate::updateAndSignalSizes()
|
||||||
{
|
{
|
||||||
|
//frame not created yet?
|
||||||
|
if (!frame) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
updateSizes(frame);
|
updateSizes(frame);
|
||||||
emit q->repaintNeeded();
|
emit q->repaintNeeded();
|
||||||
}
|
}
|
||||||
|
|
||||||
QSizeF FrameSvgPrivate::frameSize(FrameData *frame) const
|
QSizeF FrameSvgPrivate::frameSize(FrameData *frame) const
|
||||||
{
|
{
|
||||||
|
if (!frame) {
|
||||||
|
return QSizeF();
|
||||||
|
}
|
||||||
|
|
||||||
if (!frame->frameSize.isValid()) {
|
if (!frame->frameSize.isValid()) {
|
||||||
updateSizes(frame);
|
updateSizes(frame);
|
||||||
frame->frameSize = q->size();
|
frame->frameSize = q->size();
|
||||||
|
@ -36,7 +36,8 @@ class FrameData
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
FrameData(FrameSvg *svg, const QString &p)
|
FrameData(FrameSvg *svg, const QString &p)
|
||||||
: prefix(p),
|
: imagePath(svg->imagePath()),
|
||||||
|
prefix(p),
|
||||||
enabledBorders(FrameSvg::AllBorders),
|
enabledBorders(FrameSvg::AllBorders),
|
||||||
frameSize(-1, -1),
|
frameSize(-1, -1),
|
||||||
topHeight(0),
|
topHeight(0),
|
||||||
@ -57,7 +58,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
FrameData(const FrameData &other, FrameSvg *svg)
|
FrameData(const FrameData &other, FrameSvg *svg)
|
||||||
: prefix(other.prefix),
|
: imagePath(other.imagePath),
|
||||||
|
prefix(other.prefix),
|
||||||
enabledBorders(other.enabledBorders),
|
enabledBorders(other.enabledBorders),
|
||||||
cachedMasks(MAX_CACHED_MASKS),
|
cachedMasks(MAX_CACHED_MASKS),
|
||||||
frameSize(other.frameSize),
|
frameSize(other.frameSize),
|
||||||
@ -87,6 +89,7 @@ public:
|
|||||||
bool isUsed() const;
|
bool isUsed() const;
|
||||||
int refcount() const;
|
int refcount() const;
|
||||||
|
|
||||||
|
QString imagePath;
|
||||||
QString prefix;
|
QString prefix;
|
||||||
QString requestedPrefix;
|
QString requestedPrefix;
|
||||||
FrameSvg::EnabledBorders enabledBorders;
|
FrameSvg::EnabledBorders enabledBorders;
|
||||||
|
@ -536,7 +536,6 @@ QRectF SvgPrivate::elementRect(const QString &elementId)
|
|||||||
|
|
||||||
QRectF rect;
|
QRectF rect;
|
||||||
bool found = cacheAndColorsTheme()->findInRectsCache(path, id, rect);
|
bool found = cacheAndColorsTheme()->findInRectsCache(path, id, rect);
|
||||||
|
|
||||||
//This is a corner case where we are *sure* the element is not valid
|
//This is a corner case where we are *sure* the element is not valid
|
||||||
if (found && rect == QRectF()) {
|
if (found && rect == QRectF()) {
|
||||||
return rect;
|
return rect;
|
||||||
@ -551,10 +550,10 @@ QRectF SvgPrivate::elementRect(const QString &elementId)
|
|||||||
|
|
||||||
QRectF SvgPrivate::findAndCacheElementRect(const QString &elementId)
|
QRectF SvgPrivate::findAndCacheElementRect(const QString &elementId)
|
||||||
{
|
{
|
||||||
|
//we need to check the id before createRenderer(), otherwise it may generate a different id compared to the previous cacheId)( call
|
||||||
|
const QString id = cacheId(elementId);
|
||||||
createRenderer();
|
createRenderer();
|
||||||
|
|
||||||
// createRenderer() can insert some interesting rects in the cache, so check it
|
|
||||||
const QString id = cacheId(elementId);
|
|
||||||
if (localRectCache.contains(id)) {
|
if (localRectCache.contains(id)) {
|
||||||
return localRectCache.value(id);
|
return localRectCache.value(id);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user