Re: Decreasing seams in scaled windows

John Ehresman <[email protected]> Fri, 19 Jun 2026 11:08:58 +0100
Newsgroups gmane.comp.lib.scintilla.devel
Message-ID <[email protected]>
--Apple-Mail=_772A1E51-5D79-42C4-AABC-F2C7D36ED746
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain; charset="UTF-8"

Here=E2=80=99s a version that always snaps. Haven=E2=80=99t tried it with d=
efault scaling technique but should work. Also added a define to disable it=
 =E2=80=94 I do have the start of a patch to Qt that seems to work for scin=
tilla and for other widgets. The backing store has a grid of what is dirty =
and that grid is only half the size of the backing store on retina displays=
. Making it full size seems to fix the one pixel lines.

[I wrote this before seeing Neil=E2=80=99s followup message. I agree that s=
caling on macOS is less important (other than the default 2x), but it=E2=80=
=99s nice to know that the bug is not in scintilla and it actually works we=
ll when fixed]

John

--=20
You received this message because you are subscribed to the Google Groups "=
scintilla-interest" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to [email protected].
To view this discussion visit https://groups.google.com/d/msgid/scintilla-i=
nterest/4A409030-1FB4-4859-AF72-465C48263135%40wingware.com.

--Apple-Mail=_772A1E51-5D79-42C4-AABC-F2C7D36ED746
Content-Disposition: attachment;
	filename=QtScale-PlatQt.patch
Content-Type: application/octet-stream;
	x-unix-mode=0644;
	name="QtScale-PlatQt.patch"
Content-Transfer-Encoding: 7bit

diff -r 7d5e2d6cf92c qt/ScintillaEditBase/PlatQt.cpp
--- a/qt/ScintillaEditBase/PlatQt.cpp	Tue Jun 16 11:23:34 2026 +0100
+++ b/qt/ScintillaEditBase/PlatQt.cpp	Thu Jun 18 20:20:21 2026 +0100
@@ -223,6 +223,50 @@
 	return variant.toDouble();
 }
 
+// Define SCINTILLA_QT_BACKINGSTORE_FIXED when building against a Qt whose
+// backing store tracks dirty state at device-pixel resolution; that makes the
+// fractional-scaling workarounds below compile out entirely.
+
+#if defined(Q_OS_APPLE) && !defined(SCINTILLA_QT_BACKINGSTORE_FIXED)
+// Grow a logical update rect so its coordinates translate into even device
+// pixels w/o rounding. The coordinates need to be even because there's
+// a dirty grid that's 1/2 the size of the device pixel grid on Retina
+// displays. This may grow the rect more than needed on non-Retina displays
+static QRect SnapToDevicePixelGrid(QRect upd, qreal scale, QSize widgetSize)
+{
+	const int backing = (scale >= 2.0) ? 2 : 1;
+	if (backing == 1)
+		return upd;   // grid is already device-pixel resolution; nothing to snap
+
+	// q logical pixels span q * (scale/backing) grid cells.  The smallest q
+	// that makes this whole is the snap period whose multiples put logical
+	// edges on the device-pixel grid.  (scale/backing is the fractional
+	// QT_SCALE_FACTOR, e.g. 1.5 -> q == 2, 1.25 -> q == 4.)
+	const double zoom = scale / backing;
+	int q = 0;
+	for (int n = 1; n <= 8; ++n) {
+		if (std::fabs(zoom * n - std::round(zoom * n)) < 1e-4) {
+			q = n;
+			break;
+		}
+	}
+	if (q == 0)
+		return QRect();   // not a simple ratio
+	if (q == 1)
+		return upd;       // already on the grid
+
+	auto floorTo = [](int v, int n) { int r = v % n; if (r < 0) r += n; return v - r; };
+	const int l = floorTo(upd.left(),   q);
+	const int t = floorTo(upd.top(),    q);
+	const int r = floorTo(upd.right()  + q, q) - 1;   // ceil the exclusive edge
+	const int b = floorTo(upd.bottom() + q, q) - 1;
+	const QRect snapped(QPoint(l, t), QPoint(r, b));
+	if (snapped.width() >= widgetSize.width() && snapped.height() >= widgetSize.height())
+		return QRect();   // would cover the whole widget
+	return snapped;
+}
+#endif
+
 double ScaleToMultiply(WindowID wid)
 {
 	const qreal scale = ScaleOfWindow(wid);
@@ -934,18 +978,34 @@
 {
 	if (wid) {
 		const qreal scale = ScaleOfWindow(wid);
-		if (scale) {
+		QRect upd;
+		
+		if (!scale) {
+			upd = QRectFromPRect(rc);
+		}
+		else {
 #if !defined(Q_OS_WIN) && !defined(Q_OS_APPLE)
 			// Using X11 or Wayland, likely Linux but may be a BSD or similar
 			if (scale != 1.0 && scale != 2.0) {
-				// Fractional scaling leaves repaint debris, so redraw completely
 				window(wid)->update();
 				return;
 			}
 #endif
-			rc = rc / scale;
+
+			upd = QRectFFromPRect(rc / scale).toAlignedRect();
 		}
-		window(wid)->update(QRectFromPRect(rc));
+		
+#if defined(Q_OS_APPLE) && !defined(SCINTILLA_QT_BACKINGSTORE_FIXED)
+		// macOS: snap the update to the backing store's device-pixel grid.
+		const QRect snapped = SnapToDevicePixelGrid(upd, scale, window(wid)->size());
+		if (snapped.isNull()) {
+			window(wid)->update();
+			return;
+		}
+		upd = snapped;
+#endif
+
+		window(wid)->update(upd);
 	}
 }
 

--Apple-Mail=_772A1E51-5D79-42C4-AABC-F2C7D36ED746
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain; charset="UTF-8"



> On Jun 18, 2026, at 1:43=E2=80=AFAM, 'Neil Hodgson' via scintilla-interes=
t <[email protected]> wrote:
>=20
> John:
>=20
>> Attached is a patch that seems to work =E2=80=94 note that on some ratio=
s, it will revert to a full redraw. I have only tried this on macOS but pla=
n to try it on the other platforms soon.
>=20
>   This does appear to help when scale is turned on.
>=20
>   However, it may also be needed for ScaleTechnique::Default. Here is an =
image when QT_SCALE_FACTOR=3D1.5.
> https://www.scintilla.org/MacOS-Seam-150.jpg
>=20
>   Neil
>=20
> --=20
> You received this message because you are subscribed to the Google Groups=
 "scintilla-interest" group.
> To unsubscribe from this group and stop receiving emails from it, send an=
 email to [email protected].
> To view this discussion visit https://groups.google.com/d/msgid/scintilla=
-interest/9D1C1081-19AE-4845-AD70-D78C0A700D85%40me.com.

--=20
You received this message because you are subscribed to the Google Groups "=
scintilla-interest" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to [email protected].
To view this discussion visit https://groups.google.com/d/msgid/scintilla-i=
nterest/4A409030-1FB4-4859-AF72-465C48263135%40wingware.com.

--Apple-Mail=_772A1E51-5D79-42C4-AABC-F2C7D36ED746--