decoration: Fix rendering issues with scale factors < 1

QPainter::setWindow() doesn't work as we expect if the device pixel
ratio of the paint device is less than 1, for example 0.5 or 0.75.

QPainter only allows the effective device pixel ratios that are greater
than or equal to 1. This restriction probably has to be lifted.

For the time being, this change introduces a helper function that can be
used to determine the scale factor by which QPainter::window() must be
multiplied.

BUG: 432766
This commit is contained in:
Vlad Zahorodnii 2021-02-11 11:10:07 +02:00
parent 385ea10bef
commit c9ac2e3fb8
5 changed files with 18 additions and 3 deletions

View file

@ -80,7 +80,7 @@ QImage Renderer::renderToImage(const QRect &geo)
image.fill(Qt::transparent); image.fill(Qt::transparent);
QPainter p(&image); QPainter p(&image);
p.setRenderHint(QPainter::Antialiasing); p.setRenderHint(QPainter::Antialiasing);
p.setWindow(QRect(geo.topLeft(), geo.size() * dpr)); p.setWindow(QRect(geo.topLeft(), geo.size() * qPainterEffectiveDevicePixelRatio(&p)));
p.setClipRect(geo); p.setClipRect(geo);
renderToPainter(&p, geo); renderToPainter(&p, geo);
return image; return image;

View file

@ -2644,7 +2644,7 @@ void SceneOpenGLDecorationRenderer::render()
QPainter painter(&image); QPainter painter(&image);
painter.setRenderHint(QPainter::Antialiasing); painter.setRenderHint(QPainter::Antialiasing);
painter.setViewport(QRect(viewport.topLeft(), viewport.size() * devicePixelRatio)); painter.setViewport(QRect(viewport.topLeft(), viewport.size() * devicePixelRatio));
painter.setWindow(QRect(geo.topLeft(), geo.size() * devicePixelRatio)); painter.setWindow(QRect(geo.topLeft(), geo.size() * qPainterEffectiveDevicePixelRatio(&painter)));
painter.setClipRect(geo); painter.setClipRect(geo);
renderToPainter(&painter, geo); renderToPainter(&painter, geo);
painter.end(); painter.end();

View file

@ -774,7 +774,7 @@ void SceneQPainterDecorationRenderer::render()
} }
QPainter painter(&m_images[index]); QPainter painter(&m_images[index]);
painter.setRenderHint(QPainter::Antialiasing); painter.setRenderHint(QPainter::Antialiasing);
painter.setWindow(QRect(partRect.topLeft(), partRect.size() * m_images[index].devicePixelRatio())); painter.setWindow(QRect(partRect.topLeft(), partRect.size() * qPainterEffectiveDevicePixelRatio(&painter)));
painter.setClipRect(rect); painter.setClipRect(rect);
painter.save(); painter.save();
// clear existing part // clear existing part

View file

@ -16,6 +16,7 @@
#include "utils.h" #include "utils.h"
#include <QPainter>
#include <QWidget> #include <QWidget>
#include <kkeyserver.h> #include <kkeyserver.h>
@ -195,6 +196,11 @@ Qt::KeyboardModifiers x11ToQtKeyboardModifiers(int state)
return ret; return ret;
} }
qreal qPainterEffectiveDevicePixelRatio(const QPainter *painter)
{
return std::max(qreal(1), painter->device()->devicePixelRatioF());
}
} // namespace } // namespace
#ifndef KCMRULES #ifndef KCMRULES

View file

@ -119,6 +119,15 @@ void KWIN_EXPORT ungrabXServer();
bool KWIN_EXPORT grabXKeyboard(xcb_window_t w = XCB_WINDOW_NONE); bool KWIN_EXPORT grabXKeyboard(xcb_window_t w = XCB_WINDOW_NONE);
void KWIN_EXPORT ungrabXKeyboard(); void KWIN_EXPORT ungrabXKeyboard();
/**
* QPainter::setWindow() doesn't work as expected when the device pixel ratio of the paint
* device is less than 1.
*
* QPainter simply doesn't allow the effective scale factor to be less than 1. Use this function
* to determine the effective device pixel ratio by which the window rect has to be scaled.
*/
qreal KWIN_EXPORT qPainterEffectiveDevicePixelRatio(const QPainter *painter);
/** /**
* Small helper class which performs grabXServer in the ctor and * Small helper class which performs grabXServer in the ctor and
* ungrabXServer in the dtor. Use this class to ensure that grab and * ungrabXServer in the dtor. Use this class to ensure that grab and