2009-01-13 22:46:07 +01:00
|
|
|
/*
|
2020-08-13 21:08:54 +02:00
|
|
|
SPDX-FileCopyrightText: 2008 Aaron Seigo <aseigo@kde.org>
|
|
|
|
SPDX-FileCopyrightText: 2009 Marco Martin <notmart@gmail.com>
|
|
|
|
|
|
|
|
SPDX-License-Identifier: LGPL-2.0-or-later
|
|
|
|
*/
|
2009-01-13 22:46:07 +01:00
|
|
|
|
|
|
|
#ifndef PLASMA_FRAMESVG_P_H
|
|
|
|
#define PLASMA_FRAMESVG_P_H
|
|
|
|
|
2014-07-11 18:37:43 +02:00
|
|
|
#include <QCache>
|
2021-03-05 19:15:32 +01:00
|
|
|
#include <QHash>
|
2010-09-27 19:19:06 +02:00
|
|
|
#include <QStringBuilder>
|
|
|
|
|
2013-07-29 19:05:59 +02:00
|
|
|
#include <QDebug>
|
2009-01-13 22:46:07 +01:00
|
|
|
|
2013-03-12 16:29:04 +01:00
|
|
|
#include <Plasma/Theme>
|
|
|
|
|
2020-12-17 12:31:27 +01:00
|
|
|
#include "svg_p.h"
|
|
|
|
|
2009-01-13 22:46:07 +01:00
|
|
|
namespace Plasma
|
|
|
|
{
|
2014-07-21 15:44:25 +02:00
|
|
|
class FrameData
|
2009-01-13 22:46:07 +01:00
|
|
|
{
|
|
|
|
public:
|
2014-05-28 20:25:19 +02:00
|
|
|
FrameData(FrameSvg *svg, const QString &p)
|
2021-03-05 19:15:32 +01:00
|
|
|
: imagePath(svg->imagePath())
|
|
|
|
, prefix(p)
|
|
|
|
, enabledBorders(FrameSvg::AllBorders)
|
|
|
|
, frameSize(-1, -1)
|
|
|
|
, topHeight(0)
|
|
|
|
, leftWidth(0)
|
|
|
|
, rightWidth(0)
|
|
|
|
, bottomHeight(0)
|
|
|
|
, topMargin(0)
|
|
|
|
, leftMargin(0)
|
|
|
|
, rightMargin(0)
|
|
|
|
, bottomMargin(0)
|
|
|
|
, noBorderPadding(false)
|
|
|
|
, stretchBorders(false)
|
|
|
|
, tileCenter(false)
|
|
|
|
, composeOverBorder(false)
|
|
|
|
, theme(nullptr)
|
2009-01-13 22:46:07 +01:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2010-09-27 19:19:06 +02:00
|
|
|
FrameData(const FrameData &other, FrameSvg *svg)
|
2021-03-05 19:15:32 +01:00
|
|
|
: imagePath(other.imagePath)
|
|
|
|
, prefix(other.prefix)
|
|
|
|
, enabledBorders(other.enabledBorders)
|
|
|
|
, cachedMasks(MAX_CACHED_MASKS)
|
|
|
|
, frameSize(other.frameSize)
|
|
|
|
, topHeight(0)
|
|
|
|
, leftWidth(0)
|
|
|
|
, rightWidth(0)
|
|
|
|
, bottomHeight(0)
|
|
|
|
, topMargin(0)
|
|
|
|
, leftMargin(0)
|
|
|
|
, rightMargin(0)
|
|
|
|
, bottomMargin(0)
|
|
|
|
, devicePixelRatio(svg->devicePixelRatio())
|
|
|
|
, noBorderPadding(false)
|
|
|
|
, stretchBorders(false)
|
|
|
|
, tileCenter(false)
|
|
|
|
, composeOverBorder(false)
|
|
|
|
, theme(nullptr)
|
2009-01-13 22:46:07 +01:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2014-05-28 20:25:19 +02:00
|
|
|
~FrameData();
|
2009-01-13 22:46:07 +01:00
|
|
|
|
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
2017-02-28 12:37:09 +01:00
|
|
|
QString imagePath;
|
2014-05-28 20:25:19 +02:00
|
|
|
QString prefix;
|
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
2017-02-07 13:05:57 +01:00
|
|
|
QString requestedPrefix;
|
2009-01-13 22:46:07 +01:00
|
|
|
FrameSvg::EnabledBorders enabledBorders;
|
|
|
|
QPixmap cachedBackground;
|
2020-12-17 12:31:27 +01:00
|
|
|
QCache<uint, QRegion> cachedMasks;
|
2010-08-05 23:15:18 +02:00
|
|
|
static const int MAX_CACHED_MASKS = 10;
|
2020-09-22 15:03:27 +02:00
|
|
|
uint lastModified = 0;
|
2010-08-05 23:15:18 +02:00
|
|
|
|
2009-02-07 21:44:08 +01:00
|
|
|
QSize frameSize;
|
2020-12-17 12:31:27 +01:00
|
|
|
uint cacheId;
|
2009-01-13 22:46:07 +01:00
|
|
|
|
2021-03-05 19:15:32 +01:00
|
|
|
// measures
|
2009-01-13 22:46:07 +01:00
|
|
|
int topHeight;
|
|
|
|
int leftWidth;
|
|
|
|
int rightWidth;
|
|
|
|
int bottomHeight;
|
|
|
|
|
2021-03-05 19:15:32 +01:00
|
|
|
// margins, are equal to the measures by default
|
2009-01-13 22:46:07 +01:00
|
|
|
int topMargin;
|
|
|
|
int leftMargin;
|
|
|
|
int rightMargin;
|
|
|
|
int bottomMargin;
|
|
|
|
|
2021-03-05 19:15:32 +01:00
|
|
|
// measures
|
2014-02-21 21:13:12 +01:00
|
|
|
int fixedTopHeight;
|
|
|
|
int fixedLeftWidth;
|
|
|
|
int fixedRightWidth;
|
|
|
|
int fixedBottomHeight;
|
|
|
|
|
2021-03-05 19:15:32 +01:00
|
|
|
// margins, are equal to the measures by default
|
2014-02-21 21:13:12 +01:00
|
|
|
int fixedTopMargin;
|
|
|
|
int fixedLeftMargin;
|
|
|
|
int fixedRightMargin;
|
|
|
|
int fixedBottomMargin;
|
|
|
|
|
2021-03-05 19:15:32 +01:00
|
|
|
// margins, we only have the hint for insets
|
2020-11-25 18:39:12 +01:00
|
|
|
int insetTopMargin;
|
|
|
|
int insetLeftMargin;
|
|
|
|
int insetRightMargin;
|
|
|
|
int insetBottomMargin;
|
2020-11-24 18:26:58 +01:00
|
|
|
|
2015-03-25 17:06:47 +01:00
|
|
|
qreal devicePixelRatio;
|
|
|
|
|
2021-03-05 19:15:32 +01:00
|
|
|
// size of the svg where the size of the "center"
|
|
|
|
// element is contentWidth x contentHeight
|
2009-01-13 22:46:07 +01:00
|
|
|
bool noBorderPadding : 1;
|
|
|
|
bool stretchBorders : 1;
|
|
|
|
bool tileCenter : 1;
|
2010-05-06 16:16:03 +02:00
|
|
|
bool composeOverBorder : 1;
|
2010-09-27 19:19:06 +02:00
|
|
|
|
2016-03-12 13:02:34 +01:00
|
|
|
Plasma::ThemePrivate *theme;
|
2009-01-13 22:46:07 +01:00
|
|
|
};
|
|
|
|
|
2014-07-21 15:44:25 +02:00
|
|
|
class FrameSvgPrivate
|
2009-01-13 22:46:07 +01:00
|
|
|
{
|
|
|
|
public:
|
|
|
|
FrameSvgPrivate(FrameSvg *psvg)
|
2021-03-05 19:15:32 +01:00
|
|
|
: q(psvg)
|
|
|
|
, overlayPos(0, 0)
|
|
|
|
, enabledBorders(FrameSvg::AllBorders)
|
|
|
|
, cacheAll(false)
|
|
|
|
, repaintBlocked(false)
|
2009-01-13 22:46:07 +01:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2010-09-27 19:19:06 +02:00
|
|
|
~FrameSvgPrivate();
|
2009-01-13 22:46:07 +01:00
|
|
|
|
2010-03-05 23:37:44 +01:00
|
|
|
QPixmap alphaMask();
|
2010-09-27 19:19:06 +02:00
|
|
|
|
Fix binding loop regression in FrameSVGItem
Summary:
d8a1a9eb084b19e552c789244267f7346e1b27a8 introduces an unintended code
change, resizeFrame() updates the margins and in turns calls
repaintNeeded. This isn't needed and is a binding loop if we ever have a
frameSVGItem whose size depends on it's own margins.
resizeFrame is different from setEnabledBorders / setElementPrefix /
theme changes because even though we need to create a new FrameData we
know any hints and margins won't change. FrameSvgItem::updateSizes
doesn't depend on the size in any way, so always gives the same result
as before. We still, however, need to call updateSizes to populate our
FrameData structure even if the results will be the same as the previous
FrameData.
This patch that introduces a flag to updateFrameData to determine if we
should emit that size hints may have changed or not.
Test Plan:
GDB showed where the loop was.
Read the old code, and looked for differences
Ran plasmashell, checked I had no binding loop, frames including button
which have
composeOverBorder which need the new FrameData all rendered correctly.
Reviewers: #plasma, #frameworks, mart
Subscribers: mart, broulik, plasma-devel
Tags: #plasma, #frameworks
Differential Revision: https://phabricator.kde.org/D4713
2017-02-22 13:26:01 +01:00
|
|
|
enum UpdateType {
|
|
|
|
UpdateFrame,
|
2021-03-05 19:08:12 +01:00
|
|
|
UpdateFrameAndMargins,
|
Fix binding loop regression in FrameSVGItem
Summary:
d8a1a9eb084b19e552c789244267f7346e1b27a8 introduces an unintended code
change, resizeFrame() updates the margins and in turns calls
repaintNeeded. This isn't needed and is a binding loop if we ever have a
frameSVGItem whose size depends on it's own margins.
resizeFrame is different from setEnabledBorders / setElementPrefix /
theme changes because even though we need to create a new FrameData we
know any hints and margins won't change. FrameSvgItem::updateSizes
doesn't depend on the size in any way, so always gives the same result
as before. We still, however, need to call updateSizes to populate our
FrameData structure even if the results will be the same as the previous
FrameData.
This patch that introduces a flag to updateFrameData to determine if we
should emit that size hints may have changed or not.
Test Plan:
GDB showed where the loop was.
Read the old code, and looked for differences
Ran plasmashell, checked I had no binding loop, frames including button
which have
composeOverBorder which need the new FrameData all rendered correctly.
Reviewers: #plasma, #frameworks, mart
Subscribers: mart, broulik, plasma-devel
Tags: #plasma, #frameworks
Differential Revision: https://phabricator.kde.org/D4713
2017-02-22 13:26:01 +01:00
|
|
|
};
|
|
|
|
|
2018-11-20 15:31:15 +01:00
|
|
|
void generateBackground(const QSharedPointer<FrameData> &frame);
|
|
|
|
void generateFrameBackground(const QSharedPointer<FrameData> &);
|
2020-12-17 12:31:27 +01:00
|
|
|
SvgPrivate::CacheId cacheId(FrameData *frame, const QString &prefixToUse) const;
|
2009-09-28 23:02:24 +02:00
|
|
|
void cacheFrame(const QString &prefixToSave, const QPixmap &background, const QPixmap &overlay);
|
2021-03-05 19:15:32 +01:00
|
|
|
void updateSizes(FrameData *frame) const;
|
|
|
|
void updateSizes(const QSharedPointer<FrameData> &frame) const
|
|
|
|
{
|
|
|
|
return updateSizes(frame.data());
|
|
|
|
}
|
2009-01-13 22:46:07 +01:00
|
|
|
void updateNeeded();
|
|
|
|
void updateAndSignalSizes();
|
2021-03-05 19:15:32 +01:00
|
|
|
QSizeF frameSize(const QSharedPointer<FrameData> &frame) const
|
|
|
|
{
|
|
|
|
return frameSize(frame.data());
|
|
|
|
}
|
|
|
|
QSizeF frameSize(FrameData *frame) const;
|
|
|
|
void paintBorder(QPainter &p,
|
|
|
|
const QSharedPointer<FrameData> &frame,
|
|
|
|
Plasma::FrameSvg::EnabledBorders border,
|
|
|
|
const QSize &originalSize,
|
|
|
|
const QRect &output) const;
|
|
|
|
void paintCorner(QPainter &p, const QSharedPointer<FrameData> &frame, Plasma::FrameSvg::EnabledBorders border, const QRect &output) const;
|
|
|
|
void paintCenter(QPainter &p, const QSharedPointer<FrameData> &frame, const QRect &contentRect, const QSize &fullSize);
|
|
|
|
QRect contentGeometry(const QSharedPointer<FrameData> &frame, const QSize &size) const;
|
2020-09-22 15:03:27 +02:00
|
|
|
void updateFrameData(uint lastModified, UpdateType updateType = UpdateFrameAndMargins);
|
2018-11-20 15:31:15 +01:00
|
|
|
QSharedPointer<FrameData> lookupOrCreateMaskFrame(const QSharedPointer<FrameData> &frame, const QString &maskPrefix, const QString &maskRequestedPrefix);
|
2009-01-13 22:46:07 +01:00
|
|
|
|
2018-11-12 03:11:25 +01:00
|
|
|
Types::Location location = Types::Floating;
|
2009-01-13 22:46:07 +01:00
|
|
|
QString prefix;
|
2021-07-14 10:55:55 +02:00
|
|
|
// sometimes the prefix we requested is not available, so prefix will be empty
|
2021-03-05 19:15:32 +01:00
|
|
|
// keep track of the requested one anyways, we'll try again when the theme changes
|
2014-07-11 16:42:55 +02:00
|
|
|
QString requestedPrefix;
|
2009-01-13 22:46:07 +01:00
|
|
|
|
2021-03-05 19:15:32 +01:00
|
|
|
FrameSvg *const q;
|
2009-01-13 22:46:07 +01:00
|
|
|
|
|
|
|
QPoint overlayPos;
|
|
|
|
|
2018-11-20 15:31:15 +01:00
|
|
|
QSharedPointer<FrameData> frame;
|
|
|
|
QSharedPointer<FrameData> maskFrame;
|
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
2017-02-07 13:05:57 +01:00
|
|
|
|
2021-03-05 19:15:32 +01:00
|
|
|
// those can differ from frame->enabledBorders if we are in a transition
|
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
2017-02-07 13:05:57 +01:00
|
|
|
FrameSvg::EnabledBorders enabledBorders;
|
2021-03-05 19:15:32 +01:00
|
|
|
// this can differ from frame->frameSize if we are in a transition
|
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
2017-02-07 13:05:57 +01:00
|
|
|
QSize pendingFrameSize;
|
2010-09-27 19:19:06 +02:00
|
|
|
|
2021-03-05 19:15:32 +01:00
|
|
|
static QHash<ThemePrivate *, QHash<uint, QWeakPointer<FrameData>>> s_sharedFrames;
|
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
2017-02-07 13:05:57 +01:00
|
|
|
|
|
|
|
bool cacheAll : 1;
|
|
|
|
bool repaintBlocked : 1;
|
2009-01-13 22:46:07 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|