From 4484586a4d35f4a5e7a89a3ee4465701c3e3c35e Mon Sep 17 00:00:00 2001
From: Vlad Zahorodnii <vlad.zahorodnii@kde.org>
Date: Wed, 20 May 2026 12:47:14 +0000
Subject: [PATCH] v2: Fix rendering with scale factors less than 100%

It looks like FrameSvg rendering breaks with scale factors less than
100%. So, clamp the device pixel ratio for svgs to make sure that
FrameSvgs fill the decoration as expected.

BUG: 520272


(cherry picked from commit 4e4853bef948adf2af16fa858b58b87bd9e11455)

Co-authored-by: Vlad Zahorodnii <vlad.zahorodnii@kde.org>
---
 v2/decoration.cpp       | 29 +++++++++++++++--------------
 v2/decorationbutton.cpp |  9 +++++----
 v2/util.h               | 24 ++++++++++++++++++++++++
 3 files changed, 44 insertions(+), 18 deletions(-)
 create mode 100644 v2/util.h

diff --git a/v2/decoration.cpp b/v2/decoration.cpp
index f12bda1..5275f21 100644
--- a/v2/decoration.cpp
+++ b/v2/decoration.cpp
@@ -10,6 +10,7 @@
 #include "decorationbuttongroup.h"
 #include "decorationtheme.h"
 #include "decorationthemeprovider.h"
+#include "util.h"
 
 #include <KConfigGroup>
 #include <KDecoration3/DecoratedWindow>
@@ -67,43 +68,43 @@ bool Decoration::init()
     m_auroraerc = KSharedConfig::openConfig(QStringLiteral("auroraerc"));
     updateButtonSizeFactor();
 
-    const qreal devicePixelRatio = window()->scale();
+    const qreal svgDevicePixelRatio = frameSvgScale(window()->scale());
     m_decoration = std::make_unique<KSvg::FrameSvg>();
     m_decoration->setImagePath(m_theme->decorationPath());
     m_decoration->setElementPrefix(QStringLiteral("decoration"));
     m_decoration->setEnabledBorders(KSvg::FrameSvg::AllBorders);
-    m_decoration->setDevicePixelRatio(devicePixelRatio);
+    m_decoration->setDevicePixelRatio(svgDevicePixelRatio);
 
     m_decorationInactive = std::make_unique<KSvg::FrameSvg>();
     m_decorationInactive->setImagePath(m_theme->decorationPath());
     m_decorationInactive->setElementPrefix(m_decoration->hasElementPrefix(QStringLiteral("decoration-inactive")) ? QStringLiteral("decoration-inactive") : m_decoration->prefix());
     m_decorationInactive->setEnabledBorders(KSvg::FrameSvg::AllBorders);
-    m_decorationInactive->setDevicePixelRatio(devicePixelRatio);
+    m_decorationInactive->setDevicePixelRatio(svgDevicePixelRatio);
 
     m_decorationMaximized = std::make_unique<KSvg::FrameSvg>();
     m_decorationMaximized->setImagePath(m_theme->decorationPath());
     m_decorationMaximized->setElementPrefix(m_decoration->hasElementPrefix(QStringLiteral("decoration-maximized")) ? QStringLiteral("decoration-maximized") : m_decoration->prefix());
     m_decorationMaximized->setEnabledBorders(KSvg::FrameSvg::NoBorder);
-    m_decorationMaximized->setDevicePixelRatio(devicePixelRatio);
+    m_decorationMaximized->setDevicePixelRatio(svgDevicePixelRatio);
 
     m_decorationMaximizedInactive = std::make_unique<KSvg::FrameSvg>();
     m_decorationMaximizedInactive->setImagePath(m_theme->decorationPath());
     m_decorationMaximizedInactive->setElementPrefix(m_decorationInactive->hasElementPrefix(QStringLiteral("decoration-maximized-inactive")) ? QStringLiteral("decoration-maximized-inactive") : m_decorationMaximized->prefix());
     m_decorationMaximizedInactive->setEnabledBorders(KSvg::FrameSvg::NoBorder);
-    m_decorationMaximizedInactive->setDevicePixelRatio(devicePixelRatio);
+    m_decorationMaximizedInactive->setDevicePixelRatio(svgDevicePixelRatio);
 
     if (m_decoration->hasElementPrefix(QStringLiteral("innerborder"))) {
         m_innerBorder = std::make_unique<KSvg::FrameSvg>();
         m_innerBorder->setImagePath(m_theme->decorationPath());
         m_innerBorder->setElementPrefix(QStringLiteral("innerborder"));
-        m_innerBorder->setDevicePixelRatio(devicePixelRatio);
+        m_innerBorder->setDevicePixelRatio(svgDevicePixelRatio);
     }
 
     if (m_decoration->hasElementPrefix(QStringLiteral("innerborder-inactive"))) {
         m_innerBorderInactive = std::make_unique<KSvg::FrameSvg>();
         m_innerBorderInactive->setImagePath(m_theme->decorationPath());
         m_innerBorderInactive->setElementPrefix(QStringLiteral("innerborder-inactive"));
-        m_innerBorderInactive->setDevicePixelRatio(devicePixelRatio);
+        m_innerBorderInactive->setDevicePixelRatio(svgDevicePixelRatio);
     }
 
     if (m_decoration->hasElementPrefix(QStringLiteral("mask"))) {
@@ -323,18 +324,18 @@ void Decoration::onWindowCaptionChanged()
 
 void Decoration::onWindowScaleChanged()
 {
-    const qreal devicePixelRatio = window()->scale();
+    const qreal svgDevicePixelRatio = frameSvgScale(window()->scale());
 
-    m_decoration->setDevicePixelRatio(devicePixelRatio);
-    m_decorationInactive->setDevicePixelRatio(devicePixelRatio);
-    m_decorationMaximized->setDevicePixelRatio(devicePixelRatio);
-    m_decorationMaximizedInactive->setDevicePixelRatio(devicePixelRatio);
+    m_decoration->setDevicePixelRatio(svgDevicePixelRatio);
+    m_decorationInactive->setDevicePixelRatio(svgDevicePixelRatio);
+    m_decorationMaximized->setDevicePixelRatio(svgDevicePixelRatio);
+    m_decorationMaximizedInactive->setDevicePixelRatio(svgDevicePixelRatio);
 
     if (m_innerBorder) {
-        m_innerBorder->setDevicePixelRatio(devicePixelRatio);
+        m_innerBorder->setDevicePixelRatio(svgDevicePixelRatio);
     }
     if (m_innerBorderInactive) {
-        m_innerBorderInactive->setDevicePixelRatio(devicePixelRatio);
+        m_innerBorderInactive->setDevicePixelRatio(svgDevicePixelRatio);
     }
 }
 
diff --git a/v2/decorationbutton.cpp b/v2/decorationbutton.cpp
index 445d273..75a1040 100644
--- a/v2/decorationbutton.cpp
+++ b/v2/decorationbutton.cpp
@@ -5,6 +5,7 @@
 */
 
 #include "decorationbutton.h"
+#include "util.h"
 
 #include <KDecoration3/DecoratedWindow>
 
@@ -242,7 +243,7 @@ SvgDecorationButton::SvgDecorationButton(KDecoration3::DecorationButtonType type
     : DecorationButton(type, decoration, parent)
 {
     connect(decoration->window(), &KDecoration3::DecoratedWindow::scaleChanged, this, [this, decoration]() {
-        m_svgs.setDevicePixelRatio(decoration->window()->scale());
+        m_svgs.setDevicePixelRatio(frameSvgScale(decoration->window()->scale()));
     });
 
     connect(decoration->window(), &KDecoration3::DecoratedWindow::activeChanged, this, &SvgDecorationButton::updateFrame);
@@ -254,7 +255,7 @@ SvgDecorationButton::SvgDecorationButton(KDecoration3::DecorationButtonType type
 
 void SvgDecorationButton::setImagePath(const QString &path, const QSizeF &implicitSize)
 {
-    m_svgs = SvgFrameSet::from(path, implicitSize, decoration()->window()->scale());
+    m_svgs = SvgFrameSet::from(path, implicitSize, frameSvgScale(decoration()->window()->scale()));
 
     updateFrame();
     setGeometry(QRectF(QPointF(0, 0), implicitSize));
@@ -313,7 +314,7 @@ MaximizeDecorationButton::MaximizeDecorationButton(KDecoration3::Decoration *dec
     : DecorationButton(KDecoration3::DecorationButtonType::Maximize, decoration, parent)
 {
     connect(decoration->window(), &KDecoration3::DecoratedWindow::scaleChanged, this, [this, decoration]() {
-        const qreal devicePixelRatio = decoration->window()->scale();
+        const qreal devicePixelRatio = frameSvgScale(decoration->window()->scale());
 
         m_maximize.setDevicePixelRatio(devicePixelRatio);
         if (m_restore) {
@@ -336,7 +337,7 @@ MaximizeDecorationButton::MaximizeDecorationButton(KDecoration3::Decoration *dec
 
 void MaximizeDecorationButton::setImagePath(const QString &maximizeImagePath, const QString &restoreImagePath, const QSizeF &implicitSize)
 {
-    const qreal devicePixelRatio = decoration()->window()->scale();
+    const qreal devicePixelRatio = frameSvgScale(decoration()->window()->scale());
 
     m_maximize = SvgFrameSet::from(maximizeImagePath, implicitSize, devicePixelRatio);
     if (!restoreImagePath.isEmpty()) {
diff --git a/v2/util.h b/v2/util.h
new file mode 100644
index 0000000..b724e48
--- /dev/null
+++ b/v2/util.h
@@ -0,0 +1,24 @@
+/*
+    SPDX-FileCopyrightText: 2026 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
+
+    SPDX-License-Identifier: GPL-2.0-or-later
+*/
+
+#pragma once
+
+#include <QtGlobal>
+
+namespace Aurorae
+{
+
+static inline qreal frameSvgScale(qreal scale)
+{
+    // FrameSvg rendering breaks with scale factors less than 100%.
+    if (scale < 1) {
+        return 1;
+    } else {
+        return scale;
+    }
+}
+
+}
-- 
2.54.0

