Make Svg,FrameSvg work qith QT_DEVICE_PIXELRATIO

when QT_DEVICE_PIXELRATIO is something different from 1,
the pixmaps generated by Svg will be scaled up to give a proper texture.

This is complementary but not replacing our current approach:
the pixelratio that can be accessed by units is now in relation to the qt pixel ratio,
spacings are also adjusted accordingly (therefore, spaces and sizes won't
need an integer value like pixelratio)

svg introduces also a scaleFactor property (that is pretty much like its old pixelRatio)
basically, scalefactor, will scale both the textures and all the reported sizes,
(old method) pixelratio just scales textures without altering measures
(like qt pixelratio likes)

Change-Id: I304aa0d80abf76abafac239be185dd3b2ab741b7
REVIEW:122673
This commit is contained in:
Marco Martin 2015-03-10 18:02:15 +01:00
parent c9fd8fc1e5
commit 148e0022f6
8 changed files with 103 additions and 38 deletions

View File

@ -492,7 +492,12 @@ void FrameSvgItem::updateDevicePixelRatio()
{
//devicepixelratio is always set integer in the svg, so needs at least 192dpi to double up.
//(it needs to be integer to have lines contained inside a svg piece to keep being pixel aligned)
m_frameSvg->setDevicePixelRatio(qMax<qreal>(1.0, floor(m_units.devicePixelRatio())));
if (window()) {
m_frameSvg->setDevicePixelRatio(qMax<qreal>(1.0, floor(window()->devicePixelRatio())));
} else {
m_frameSvg->setDevicePixelRatio(qMax<qreal>(1.0, floor(qApp->devicePixelRatio())));
}
m_frameSvg->setScaleFactor(qMax<qreal>(1.0, floor(m_units.devicePixelRatio())));
m_textureChanged = true;
}

View File

@ -115,6 +115,7 @@ void IconItem::setSource(const QVariant &source)
if (!m_svgIcon) {
m_svgIcon = new Plasma::Svg(this);
m_svgIcon->setColorGroup(m_colorGroup);
m_svgIcon->setDevicePixelRatio((window() ? window()->devicePixelRatio() : qApp->devicePixelRatio()));
}
//try as a svg icon
m_svgIcon->setImagePath("icons/" + source.toString().split("-").first());
@ -322,7 +323,7 @@ void IconItem::loadPixmap()
m_svgIcon->resize(size, size);
result = m_svgIcon->pixmap(m_source.toString());
} else if (!m_icon.isNull()) {
result = m_icon.pixmap(QSize(size, size));
result = m_icon.pixmap(QSize(size, size) * (window() ? window()->devicePixelRatio() : qApp->devicePixelRatio()));
} else if (!m_pixmapIcon.isNull()) {
result = m_pixmapIcon;
} else if (!m_imageIcon.isNull()) {

View File

@ -198,7 +198,12 @@ void SvgItem::updateDevicePixelRatio()
if (m_svg) {
//devicepixelratio is always set integer in the svg, so needs at least 192dpi to double up.
//(it needs to be integer to have lines contained inside a svg piece to keep being pixel aligned)
m_svg.data()->setDevicePixelRatio(qMax<qreal>(1.0, floor(m_units.devicePixelRatio())));
if (window()) {
m_svg.data()->setDevicePixelRatio(qMax<qreal>(1.0, floor(window()->devicePixelRatio())));
} else {
m_svg.data()->setDevicePixelRatio(qMax<qreal>(1.0, floor(qApp->devicePixelRatio())));
}
m_svg.data()->setScaleFactor(qMax<qreal>(1.0, floor(m_units.devicePixelRatio())));
}
}

View File

@ -206,6 +206,7 @@ int Units::largeSpacing() const
void Units::updateSpacing()
{
int gridUnit = QFontMetrics(QGuiApplication::font()).boundingRect("M").height();
if (gridUnit % 2 != 0) {
gridUnit++;
}

View File

@ -791,7 +791,7 @@ void FrameSvgPrivate::generateBackground(FrameData *frame)
void FrameSvgPrivate::generateFrameBackground(FrameData *frame)
{
//qDebug() << "generating background";
const QSize size = frameSize(frame).toSize();
const QSize size = frameSize(frame).toSize() * q->devicePixelRatio();
if (!size.isValid()) {
#ifndef NDEBUG
@ -820,25 +820,29 @@ void FrameSvgPrivate::generateFrameBackground(FrameData *frame)
// Sides
const int leftHeight = q->elementSize(prefix % "left").height();
paintBorder(p, frame, FrameSvg::LeftBorder, QSize(frame->leftWidth, leftHeight), contentRect);
paintBorder(p, frame, FrameSvg::RightBorder, QSize(frame->rightWidth, leftHeight), 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);
const int topWidth = q->elementSize(prefix % "top").width();
paintBorder(p, frame, FrameSvg::TopBorder, QSize(topWidth, frame->topHeight), contentRect);
paintBorder(p, frame, FrameSvg::BottomBorder, QSize(topWidth, frame->bottomHeight), 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);
p.end();
frame->cachedBackground.setDevicePixelRatio(q->devicePixelRatio());
}
QRect FrameSvgPrivate::contentGeometry(FrameData* frame, const QSize& size) const
{
const QSize contentSize(size.width() - frame->leftWidth - frame->rightWidth, size.height() - frame->topHeight - frame->bottomHeight);
const QSize contentSize(size.width() - frame->leftWidth * q->devicePixelRatio() - frame->rightWidth * q->devicePixelRatio(),
size.height() - frame->topHeight * q->devicePixelRatio() - frame->bottomHeight * q->devicePixelRatio());
QRect contentRect(QPoint(0,0), contentSize);
if (frame->enabledBorders & FrameSvg::LeftBorder && q->hasElement(prefix % "left")) {
contentRect.translate(frame->leftWidth, 0);
contentRect.translate(frame->leftWidth * q->devicePixelRatio(), 0);
}
// Corners
if (frame->enabledBorders & FrameSvg::TopBorder && q->hasElement(prefix % "top")) {
contentRect.translate(0, frame->topHeight);
contentRect.translate(0, frame->topHeight * q->devicePixelRatio());
}
return contentRect;
}
@ -859,14 +863,14 @@ void FrameSvgPrivate::paintCenter(QPainter& p, FrameData* frame, const QRect& co
if (frame->composeOverBorder) {
p.drawTiledPixmap(QRect(QPoint(0, 0), fullSize), center);
} else {
p.drawTiledPixmap(FrameSvgHelpers::sectionRect(FrameSvg::NoBorder, contentRect, fullSize), center);
p.drawTiledPixmap(FrameSvgHelpers::sectionRect(FrameSvg::NoBorder, contentRect, fullSize * q->devicePixelRatio()), center);
}
} else {
if (frame->composeOverBorder) {
q->paint(&p, QRect(QPoint(0, 0), fullSize),
centerElementId);
} else {
q->paint(&p, FrameSvgHelpers::sectionRect(FrameSvg::NoBorder, contentRect, fullSize), centerElementId);
q->paint(&p, FrameSvgHelpers::sectionRect(FrameSvg::NoBorder, contentRect, fullSize * q->devicePixelRatio()), centerElementId);
}
}
}
@ -883,7 +887,7 @@ void FrameSvgPrivate::paintBorder(QPainter& p, FrameData* frame, const FrameSvg:
QString side = prefix % FrameSvgHelpers::borderToElementId(borders);
if (frame->enabledBorders & borders && q->hasElement(side) && !size.isEmpty()) {
if (frame->stretchBorders) {
q->paint(&p, FrameSvgHelpers::sectionRect(borders, contentRect, frame->frameSize), side);
q->paint(&p, FrameSvgHelpers::sectionRect(borders, contentRect, frame->frameSize * q->devicePixelRatio()), side);
} else {
QPixmap px(size);
px.fill(Qt::transparent);
@ -892,7 +896,7 @@ void FrameSvgPrivate::paintBorder(QPainter& p, FrameData* frame, const FrameSvg:
sidePainter.setCompositionMode(QPainter::CompositionMode_Source);
q->paint(&sidePainter, QRect(QPoint(0, 0), size), side);
p.drawTiledPixmap(FrameSvgHelpers::sectionRect(borders, contentRect, frame->frameSize), px);
p.drawTiledPixmap(FrameSvgHelpers::sectionRect(borders, contentRect, frame->frameSize * q->devicePixelRatio()), px);
}
}
}
@ -901,7 +905,7 @@ void FrameSvgPrivate::paintCorner(QPainter& p, FrameData* frame, Plasma::FrameSv
{
QString corner = prefix % FrameSvgHelpers::borderToElementId(border);
if (frame->enabledBorders & border && q->hasElement(corner)) {
q->paint(&p, FrameSvgHelpers::sectionRect(border, contentRect, frame->frameSize), corner);
q->paint(&p, FrameSvgHelpers::sectionRect(border, contentRect, frame->frameSize * q->devicePixelRatio()), corner);
}
}
@ -909,7 +913,7 @@ QString FrameSvgPrivate::cacheId(FrameData *frame, const QString &prefixToSave)
{
const QSize size = frameSize(frame).toSize();
const QLatin1Char s('_');
return QString::number(frame->enabledBorders) % s % QString::number(size.width()) % s % QString::number(size.height()) % 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 % q->imagePath();
}
void FrameSvgPrivate::cacheFrame(const QString &prefixToSave, const QPixmap &background, const QPixmap &overlay)

View File

@ -72,7 +72,7 @@ public:
Theme *actualTheme();
Theme *cacheAndColorsTheme();
QPixmap findInCache(const QString &elementId, const QSizeF &s = QSizeF());
QPixmap findInCache(const QString &elementId, qreal ratio, const QSizeF &s = QSizeF());
void createRenderer();
void eraseRenderer();
@ -109,6 +109,7 @@ public:
Theme::ColorGroup colorGroup;
unsigned int lastModified;
qreal devicePixelRatio;
qreal scaleFactor;
bool multipleImages : 1;
bool themed : 1;
bool fromCurrentTheme : 1;

View File

@ -129,8 +129,8 @@ bool SharedSvgRenderer::load(
}
#define QLSEP QLatin1Char('_')
#define CACHE_ID_WITH_SIZE(size, id, devicePixelRatio) QString::number(int(size.width())) % QLSEP % QString::number(int(size.height())) % QLSEP % id % QLSEP % QString::number(int(devicePixelRatio))
#define CACHE_ID_NATURAL_SIZE(id, devicePixelRatio) QLatin1Literal("Natural") % QLSEP % id % QLSEP % QString::number(int(devicePixelRatio))
#define CACHE_ID_WITH_SIZE(size, id, devicePixelRatio) QString::number(int(size.width())) % QLSEP % QString::number(int(size.height())) % QLSEP % id % QLSEP % QLSEP % QString::number(int(devicePixelRatio))
#define CACHE_ID_NATURAL_SIZE(id, devicePixelRatio) QLatin1Literal("Natural") % QLSEP % id % QLSEP % QLSEP % QString::number(int(devicePixelRatio))
SvgPrivate::SvgPrivate(Svg *svg)
: q(svg),
@ -139,6 +139,7 @@ SvgPrivate::SvgPrivate(Svg *svg)
colorGroup(Plasma::Theme::NormalColorGroup),
lastModified(0),
devicePixelRatio(1.0),
scaleFactor(1.0),
multipleImages(false),
themed(false),
fromCurrentTheme(false),
@ -237,7 +238,7 @@ bool SvgPrivate::setImagePath(const QString &imagePath)
naturalSize = rect.size();
} else {
createRenderer();
naturalSize = renderer->defaultSize() * devicePixelRatio;
naturalSize = renderer->defaultSize() * scaleFactor;
//qDebug() << "natural size for" << path << "from renderer is" << naturalSize;
cacheAndColorsTheme()->insertIntoRectsCache(path, "_Natural", QRectF(QPointF(0, 0), naturalSize));
//qDebug() << "natural size for" << path << "from cache is" << naturalSize;
@ -279,7 +280,7 @@ Theme *SvgPrivate::cacheAndColorsTheme()
}
}
QPixmap SvgPrivate::findInCache(const QString &elementId, const QSizeF &s)
QPixmap SvgPrivate::findInCache(const QString &elementId, qreal ratio, const QSizeF &s)
{
QSize size;
QString actualElementId;
@ -287,7 +288,7 @@ QPixmap SvgPrivate::findInCache(const QString &elementId, const QSizeF &s)
if (elementsWithSizeHints.isEmpty()) {
// Fetch all size hinted element ids from the theme's rect cache
// and store them locally.
QRegExp sizeHintedKeyExpr(CACHE_ID_NATURAL_SIZE("(\\d+)-(\\d+)-(.+)", devicePixelRatio));
QRegExp sizeHintedKeyExpr(CACHE_ID_NATURAL_SIZE("(\\d+)-(\\d+)-(.+)", ratio));
foreach (const QString &key, cacheAndColorsTheme()->listCachedRectKeys(path)) {
if (sizeHintedKeyExpr.exactMatch(key)) {
@ -317,7 +318,7 @@ QPixmap SvgPrivate::findInCache(const QString &elementId, const QSizeF &s)
Q_FOREACH (const QSize &hint, elementSizeHints) {
if (hint.width() >= s.width() && hint.height() >= s.height() &&
if (hint.width() >= s.width() * ratio && hint.height() >= s.height() * ratio &&
(!bestFit.isValid() ||
(bestFit.width() * bestFit.height()) > (hint.width() * hint.height()))) {
bestFit = hint;
@ -336,9 +337,9 @@ QPixmap SvgPrivate::findInCache(const QString &elementId, const QSizeF &s)
}
if (elementId.isEmpty() || (multipleImages && s.isValid())) {
size = s.toSize();
size = s.toSize() * ratio;
} else {
size = elementRect(actualElementId).size().toSize();
size = elementRect(actualElementId).size().toSize() * ratio;
}
if (size.isEmpty()) {
@ -355,6 +356,7 @@ QPixmap SvgPrivate::findInCache(const QString &elementId, const QSizeF &s)
QPixmap p;
if (cacheRendering && cacheAndColorsTheme()->findInCache(id, p, lastModified)) {
p.setDevicePixelRatio(ratio);
//qDebug() << "found cached version of " << id << p.size();
return p;
}
@ -382,6 +384,7 @@ QPixmap SvgPrivate::findInCache(const QString &elementId, const QSizeF &s)
}
renderPainter.end();
p.setDevicePixelRatio(ratio);
// Apply current color scheme if the svg asks for it
if (applyColors) {
@ -543,7 +546,7 @@ QRectF SvgPrivate::findAndCacheElementRect(const QString &elementId)
qreal dy = size.height() / naturalSize.height();
elementRect = QRectF(elementRect.x() * dx, elementRect.y() * dy,
elementRect.width() * dx * devicePixelRatio, elementRect.height() * dy * devicePixelRatio);
elementRect.width() * dx * scaleFactor, elementRect.height() * dy * scaleFactor);
cacheAndColorsTheme()->insertIntoRectsCache(path, id, elementRect);
@ -707,8 +710,8 @@ void Svg::setDevicePixelRatio(qreal ratio)
}
d->devicePixelRatio = floor(ratio);
emit repaintNeeded();
emit sizeChanged();
}
qreal Svg::devicePixelRatio()
@ -716,6 +719,27 @@ qreal Svg::devicePixelRatio()
return d->devicePixelRatio;
}
void Svg::setScaleFactor(qreal ratio)
{
//be completely integer for now
//devicepixelratio is always set integer in the svg, so needs at least 192dpi to double up.
//(it needs to be integer to have lines contained inside a svg piece to keep being pixel aligned)
if (floor(d->scaleFactor) == floor(ratio)) {
return;
}
d->scaleFactor = floor(ratio);
emit repaintNeeded();
emit sizeChanged();
}
qreal Svg::scaleFactor() const
{
return d->scaleFactor;
}
void Svg::setColorGroup(Plasma::Theme::ColorGroup group)
{
if (d->colorGroup == group) {
@ -736,28 +760,30 @@ Plasma::Theme::ColorGroup Svg::colorGroup() const
QPixmap Svg::pixmap(const QString &elementID)
{
if (elementID.isNull() || d->multipleImages) {
return d->findInCache(elementID, size());
return d->findInCache(elementID, d->devicePixelRatio, size());
} else {
return d->findInCache(elementID);
return d->findInCache(elementID, d->devicePixelRatio);
}
}
QImage Svg::image(const QSize &size, const QString &elementID)
{
QPixmap pix(d->findInCache(elementID, size));
QPixmap pix(d->findInCache(elementID, d->devicePixelRatio, size));
return pix.toImage();
}
void Svg::paint(QPainter *painter, const QPointF &point, const QString &elementID)
{
QPixmap pix((elementID.isNull() || d->multipleImages) ? d->findInCache(elementID, size()) :
d->findInCache(elementID));
Q_ASSERT(painter->device());
const int ratio = painter->device()->devicePixelRatio();
QPixmap pix((elementID.isNull() || d->multipleImages) ? d->findInCache(elementID, ratio, size()) :
d->findInCache(elementID, ratio));
if (pix.isNull()) {
return;
}
painter->drawPixmap(QRectF(point, pix.size()), pix, QRectF(QPointF(0, 0), pix.size()));
painter->drawPixmap(QRectF(point, size()), pix, QRectF(QPointF(0, 0), pix.size()));
}
void Svg::paint(QPainter *painter, int x, int y, const QString &elementID)
@ -767,13 +793,18 @@ void Svg::paint(QPainter *painter, int x, int y, const QString &elementID)
void Svg::paint(QPainter *painter, const QRectF &rect, const QString &elementID)
{
QPixmap pix(d->findInCache(elementID, rect.size()));
painter->drawPixmap(QRectF(rect.topLeft(), pix.size()), pix, QRectF(QPointF(0, 0), pix.size()));
Q_ASSERT(painter->device());
const int ratio = painter->device()->devicePixelRatio();
QPixmap pix(d->findInCache(elementID, ratio, rect.size()));
painter->drawPixmap(QRectF(rect.topLeft(), rect.size()), pix, QRectF(QPointF(0, 0), pix.size()));
}
void Svg::paint(QPainter *painter, int x, int y, int width, int height, const QString &elementID)
{
QPixmap pix(d->findInCache(elementID, QSizeF(width, height)));
Q_ASSERT(painter->device());
const int ratio = painter->device()->devicePixelRatio();
QPixmap pix(d->findInCache(elementID, ratio, QSizeF(width, height)));
painter->drawPixmap(x, y, pix, 0, 0, pix.size().width(), pix.size().height());
}

View File

@ -85,7 +85,9 @@ public:
/**
* Set the device pixel ratio for the Svg. This is the ratio between
* image pixels and device-independent pixels.
* The default value is 1.0.
* The Svg will produce pixmaps scaled by devicePixelRatio, but all the sizes and element
* rects will not be altered.
* The default value is 1.0 and the scale will be done rounded to the floor integer
* Setting it to something more, will make all the elements of this svg appear bigger.
*/
void setDevicePixelRatio(qreal ratio);
@ -95,6 +97,21 @@ public:
*/
qreal devicePixelRatio();
/**
* Settng a scale factor greater than one it will result in final images scaled by it.
* Unlike devicePixelRatio, every size and element rect will be scaled accordingly.
* @return how much to scale the rendered image.
*/
qreal scaleFactor() const;
/**
* Settng a scale factor greater than one it will result in final images scaled by it.
* Unlike devicePixelRatio, every size and element rect will be scaled accordingly.
* The default value is 1.0 and the scale will be done rounded to the floor integer.
* @param how much to scale the Svg
*/
void setScaleFactor(qreal factor);
/**
* Set a color group for the Svg.
* if the Svg uses stylesheets and has elements