From 30357e55d1bd86fd2ae207160c930b7cf5d8a5dd Mon Sep 17 00:00:00 2001 From: Eirik Aavitsland Date: Tue, 28 Jun 2022 09:32:09 +0200 Subject: [PATCH] Improve widget painting under dpr>1 by enabling smooth pixmap scaling Smooth scaling of icons etc. give far better visual results, particularly with fractional dpr scaling. So enable this generally in QStylePainter, and make more of the relevant widgets use QStylePainter instead of QPainter directly. Differences can be seen in the widgets examples, e.g. textedit, gallery, stylesheet (Pagefold), mdi. Task-number: QTBUG-96223 Fixes: QTBUG-101058 Change-Id: I3c34a455d097e5f6a6a09d3b020528b4fbda4d85 Reviewed-by: Richard Moe Gustavsen Reviewed-by: Volker Hilsheimer (cherry picked from commit c78ec505293ed576779c0ee7342746cde39281d6) Reviewed-by: Qt Cherry-pick Bot --- src/widgets/dialogs/qwizard.cpp | 6 +++--- src/widgets/itemviews/qlistview.cpp | 8 ++++---- src/widgets/kernel/qwidget.cpp | 1 + src/widgets/styles/qstylepainter.h | 4 +++- src/widgets/widgets/qlabel.cpp | 8 +++++--- src/widgets/widgets/qmenu.cpp | 12 ++++++------ src/widgets/widgets/qsizegrip.cpp | 6 +++--- 7 files changed, 25 insertions(+), 20 deletions(-) diff --git a/src/widgets/dialogs/qwizard.cpp b/src/widgets/dialogs/qwizard.cpp index 79a83da33a1..5b95b62772e 100644 --- a/src/widgets/dialogs/qwizard.cpp +++ b/src/widgets/dialogs/qwizard.cpp @@ -18,7 +18,7 @@ #include "qlineedit.h" #endif #include -#include "qpainter.h" +#include "qstylepainter.h" #include "qwindow.h" #include "qpushbutton.h" #include "qset.h" @@ -386,7 +386,7 @@ void QWizardHeader::setup(const QWizardLayoutInfo &info, const QString &title, void QWizardHeader::paintEvent(QPaintEvent * /* event */) { - QPainter painter(this); + QStylePainter painter(this); painter.drawPixmap(0, 0, bannerPixmap); int x = width() - 2; @@ -3231,7 +3231,7 @@ void QWizard::paintEvent(QPaintEvent * event) if (backgroundPixmap.isNull()) return; - QPainter painter(this); + QStylePainter painter(this); painter.drawPixmap(0, (height() - backgroundPixmap.height()) / 2, backgroundPixmap); } #if QT_CONFIG(style_windowsvista) diff --git a/src/widgets/itemviews/qlistview.cpp b/src/widgets/itemviews/qlistview.cpp index 7f8f7a20fef..30bf327af7a 100644 --- a/src/widgets/itemviews/qlistview.cpp +++ b/src/widgets/itemviews/qlistview.cpp @@ -9,7 +9,7 @@ #include #endif #include -#include +#include #include #include #if QT_CONFIG(draganddrop) @@ -988,7 +988,7 @@ void QListView::paintEvent(QPaintEvent *e) return; QStyleOptionViewItem option; initViewItemOption(&option); - QPainter painter(d->viewport); + QStylePainter painter(d->viewport); const QList toBeRendered = d->intersectingSet(e->rect().translated(horizontalOffset(), verticalOffset()), false); @@ -1059,7 +1059,7 @@ void QListView::paintEvent(QPaintEvent *e) // is provided by the delegate QStyle::State oldState = option.state; option.state &= ~QStyle::State_Selected; - style()->drawPrimitive(QStyle::PE_PanelItemViewRow, &option, &painter, this); + painter.drawPrimitive(QStyle::PE_PanelItemViewRow, option); option.state = oldState; alternateBase = !alternateBase; @@ -1083,7 +1083,7 @@ void QListView::paintEvent(QPaintEvent *e) opt.rect = d->mapToViewport(d->elasticBand, false).intersected( d->viewport->rect().adjusted(-16, -16, 16, 16)); painter.save(); - style()->drawControl(QStyle::CE_RubberBand, &opt, &painter); + painter.drawControl(QStyle::CE_RubberBand, opt); painter.restore(); } #endif diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index f0da19f9c8c..ab129b73e70 100644 --- a/src/widgets/kernel/qwidget.cpp +++ b/src/widgets/kernel/qwidget.cpp @@ -5529,6 +5529,7 @@ void QWidgetPrivate::drawWidget(QPaintDevice *pdev, const QRegion &rgn, const QP && !q->testAttribute(Qt::WA_OpaquePaintEvent) && !q->testAttribute(Qt::WA_NoSystemBackground)) { beginBackingStorePainting(); QPainter p(q); + p.setRenderHint(QPainter::SmoothPixmapTransform); paintBackground(&p, toBePainted, (asRoot || onScreen) ? (flags | DrawAsRoot) : DrawWidgetFlags()); endBackingStorePainting(); } diff --git a/src/widgets/styles/qstylepainter.h b/src/widgets/styles/qstylepainter.h index 8243ff5f39f..65664b776e2 100644 --- a/src/widgets/styles/qstylepainter.h +++ b/src/widgets/styles/qstylepainter.h @@ -23,7 +23,9 @@ public: Q_ASSERT_X(w, "QStylePainter::QStylePainter", "Widget must be non-zero"); widget = w; wstyle = w->style(); - return QPainter::begin(pd); + const bool res = QPainter::begin(pd); + setRenderHint(QPainter::SmoothPixmapTransform); + return res; }; inline void drawPrimitive(QStyle::PrimitiveElement pe, const QStyleOption &opt); inline void drawControl(QStyle::ControlElement ce, const QStyleOption &opt); diff --git a/src/widgets/widgets/qlabel.cpp b/src/widgets/widgets/qlabel.cpp index 3e06360920f..4d1c4ebb741 100644 --- a/src/widgets/widgets/qlabel.cpp +++ b/src/widgets/widgets/qlabel.cpp @@ -1091,8 +1091,10 @@ void QLabel::paintEvent(QPaintEvent *) #endif if (d->pixmap && !d->pixmap->isNull()) { QPixmap pix; - if (d->scaledcontents) { - QSize scaledSize = cr.size() * devicePixelRatio(); + const qreal dpr = devicePixelRatio(); + if (d->scaledcontents || dpr != d->pixmap->devicePixelRatio()) { + QSize scaledSize = d->scaledcontents ? (cr.size() * dpr) + : (d->pixmap->size() * (dpr / d->pixmap->devicePixelRatio())); if (!d->scaledpixmap || d->scaledpixmap->size() != scaledSize) { if (!d->cachedimage) d->cachedimage = d->pixmap->toImage(); @@ -1101,7 +1103,7 @@ void QLabel::paintEvent(QPaintEvent *) d->cachedimage->scaled(scaledSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); d->scaledpixmap = QPixmap::fromImage(std::move(scaledImage)); - d->scaledpixmap->setDevicePixelRatio(devicePixelRatio()); + d->scaledpixmap->setDevicePixelRatio(dpr); } pix = *d->scaledpixmap; } else diff --git a/src/widgets/widgets/qmenu.cpp b/src/widgets/widgets/qmenu.cpp index 89b09716cc9..93f8610801e 100644 --- a/src/widgets/widgets/qmenu.cpp +++ b/src/widgets/widgets/qmenu.cpp @@ -12,7 +12,7 @@ #include "qevent.h" #include "qtimer.h" #include "qlayout.h" -#include "qpainter.h" +#include "qstylepainter.h" #include #include "qapplication.h" #if QT_CONFIG(accessibility) @@ -2695,7 +2695,7 @@ void QMenu::paintEvent(QPaintEvent *e) { Q_D(QMenu); d->updateActionRects(); - QPainter p(this); + QStylePainter p(this); QRegion emptyArea = QRegion(rect()); QStyleOptionMenuItem menuOpt; @@ -2704,7 +2704,7 @@ void QMenu::paintEvent(QPaintEvent *e) menuOpt.checkType = QStyleOptionMenuItem::NotCheckable; menuOpt.maxIconWidth = 0; menuOpt.reservedShortcutWidth = 0; - style()->drawPrimitive(QStyle::PE_PanelMenu, &menuOpt, &p, this); + p.drawPrimitive(QStyle::PE_PanelMenu, menuOpt); //calculate the scroll up / down rect const int fw = style()->pixelMetric(QStyle::PM_MenuPanelWidth, nullptr, this); @@ -2772,7 +2772,7 @@ void QMenu::paintEvent(QPaintEvent *e) QStyleOptionMenuItem opt; initStyleOption(&opt, action); opt.rect = actionRect; - style()->drawControl(QStyle::CE_MenuItem, &opt, &p, this); + p.drawControl(QStyle::CE_MenuItem, opt); } emptyArea -= QRegion(scrollUpTearOffRect); @@ -2806,7 +2806,7 @@ void QMenu::paintEvent(QPaintEvent *e) frame.state = QStyle::State_None; frame.lineWidth = style()->pixelMetric(QStyle::PM_MenuPanelWidth, &frame); frame.midLineWidth = 0; - style()->drawPrimitive(QStyle::PE_FrameMenu, &frame, &p, this); + p.drawPrimitive(QStyle::PE_FrameMenu, frame); } //finally the rest of the spaces @@ -2816,7 +2816,7 @@ void QMenu::paintEvent(QPaintEvent *e) menuOpt.checkType = QStyleOptionMenuItem::NotCheckable; menuOpt.rect = rect(); menuOpt.menuRect = rect(); - style()->drawControl(QStyle::CE_MenuEmptyArea, &menuOpt, &p, this); + p.drawControl(QStyle::CE_MenuEmptyArea, menuOpt); } #if QT_CONFIG(wheelevent) diff --git a/src/widgets/widgets/qsizegrip.cpp b/src/widgets/widgets/qsizegrip.cpp index 0e6ac5332a9..8ffcb0081bd 100644 --- a/src/widgets/widgets/qsizegrip.cpp +++ b/src/widgets/widgets/qsizegrip.cpp @@ -5,7 +5,7 @@ #include "qapplication.h" #include "qevent.h" -#include "qpainter.h" +#include "qstylepainter.h" #include "qwindow.h" #include #include "qstyle.h" @@ -212,11 +212,11 @@ void QSizeGrip::paintEvent(QPaintEvent *event) { Q_UNUSED(event); Q_D(QSizeGrip); - QPainter painter(this); + QStylePainter painter(this); QStyleOptionSizeGrip opt; opt.initFrom(this); opt.corner = d->m_corner; - style()->drawControl(QStyle::CE_SizeGrip, &opt, &painter, this); + painter.drawControl(QStyle::CE_SizeGrip, opt); } /*!