Decreasing seams in scaled windows

84 views
Skip to first unread message

Neil

unread,
Mar 4, 2026, 1:08:24 AMMar 4
to scintilla-interest
In some circumstances, when a Scintilla window is scaled by a fractional amount like 1.5x or 1.25x, visual anomalies occur between filled rectangles. The window background may show through because the rectangles before and after or above and below only partially draw shared pixels.

This can be seen in this image with Qt 6 on Win32 with 1.25x scaling.

This was reported in some bug tracker issues and in the "Scintilla GTK 4 port" thread.
In that thread, a couple of patches decrease the severity of the seams but do not eliminate them.

I believe the highest quality output will be produced when Scintilla is drawing to raw screen pixels and the text is scaled to match the window scaling factor. However, some platforms may make this difficult or impossible to accomplish so some improvements can be made.

[Overdraw by 1 pixel]

One technique to cover seams is to draw more than required to ensure that each pixel is completely covered by at least one filled rectangle call. Extending the area of each opaque background rectangle by 1 (logical) pixel horizontally and vertically can achieve this. Almost all background drawing occurs left-to-right & top-to-bottom, so each of these oversized rectangles will then have a following rectangle merge nicely on its leading pixel as it will only see the colour of the preceding rectangle, with no trace of the window background.

If the scaling factor is less than 1.0x (0.5x?), a larger extension may be needed.

This technique improves over the proposal to clear the whole window to a global background colour as it will work better with areas (like JavaScript in a HTML page) that use a different background colour.

There are problems with extending this to translucent drawing as a translucent drawing call will have different results when performed more times.

An incomplete implementation of this is available from

The results can be seen with the same text as above.
There are faint seams in the selection as it uses translucency and these will be more prominent when the selection colour differs more from the text background. There is a vertical seam between the line number and marker margins as the implementation is currently only for EditView. 

This code is slower and could potentially cause flicker due to drawing some pixels multiple times. It only works in unbuffered mode and with SCI_SETPHASESDRAW(SC_PHASES_MULTIPLE) since it draws outside the strict line rectangles used in other modes.

This mode could be controlled by the application or Scintilla platform layer code or a combination. It is really only helpful when the window is scaled fractionally and this may be determined by the platform layer. It may change as the window is moved between screens and will be an extra chore for the application to manage.

Its likely that the referenced patch will grow as more elements need to handle it. I think the visible line end mode is one that needs to change. The way seamOverDraw is passed around is ugly and may have unforeseen effects: this could cause different results when printing, for example.

Neil

Mitchell

unread,
Mar 4, 2026, 10:25:19 AMMar 4
to scintilla...@googlegroups.com
Hi Neil,
The curses (terminal) platform treats each pixel as a cell, so it is very sensitive to any rectangle size changes. I haven’t tested this patch, but I’d like to know if this “overdrawing” can be optional. Or maybe the overdraw parameters can be ignored by the platform? (It’s hard for me to understand the patch by reading it by itself.)

I’d appreciate any thoughts you might have on this.

Cheers,
Mitchell

Neil

unread,
Mar 4, 2026, 4:19:42 PMMar 4
to scintilla-interest
Mitchell:
I haven’t tested this patch, but I’d like to know if this “overdrawing” can be optional. Or maybe the overdraw parameters can be ignored by the platform? (It’s hard for me to understand the patch by reading it by itself.)

Yes, the overdraw will be optional and it may be up to the platform layer to enable it.

Perhaps overdraw is completely determined by the platform layer. Or there could be an API.

The decision could be a combination of the platform layer and an API.

There are other APIs like `SCI_SETTECHNOLOGY` and `SCI_SETBIDIRECTIONAL` where some platform layers intercept the call to restrict the possibilities such as refusing bidirectional mode.

Sometimes scaling information is available at an application level but is not easily available from a widget. On Win32, for example, some messages only go to topmost windows.

In the opposite direction, requiring applications to use an API means this will be less automatic which will lead to a poorer default experience.

The patch does not include an API or any platform enabling since its just trying to see if the idea is workable.

Neil 

John Ehresman

unread,
Mar 4, 2026, 11:40:46 PMMar 4
to scintilla...@googlegroups.com
Apologies for not looking into this sooner. I think Qt can render to the raw screen or device pixels (or at least the backing pixmap that Qt draws to before sending to the screen).

The way to simulate / adjust the scaling factor is to use the QT_SCALE_FACTOR environment variable; e.g QT_SCALE_FACTOR=1.5 testprogram

One way to draw to raw pixels is to render to a full size pixmap, set the device pixel ratio to match the widget, then render the pixmap to the widget.

It also may be possible to set the scale on a painter to 1 / device-pixel-ratio and then draw.

I may be able to try to fix this in scintilla, but it probably won’t be immediately.

John
> --
> 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 scintilla-inter...@googlegroups.com.
> To view this discussion visit https://groups.google.com/d/msgid/scintilla-interest/5530760c-3b48-4610-8c57-0ec3fc6381den%40googlegroups.com.

Neil

unread,
Mar 6, 2026, 7:17:37 PMMar 6
to scintilla-interest
John:

One way to draw to raw pixels is to render to a full size pixmap, set the device pixel ratio to match the widget, then render the pixmap to the widget.

It also may be possible to set the scale on a painter to 1 / device-pixel-ratio and then draw.

These will be better approaches.

The earlier patch on this thread is improved a bit in case it is needed for other platforms.

This applies to the current repository state since a recent commit reduced draw calls for visible whitespace background by using a single call for a sequence of spaces instead on one call per space. Its faster and removes seams between spaces.

The Larger3.patch change moves the controlling variable to ViewState where it can be set differently for screen and printer. The decision is now made in the platform layer inside ScintillaQt.cpp. Seam overdraw is turned off for integer scaling 1x and 2x and also, to allow experimentation, for 1.5x.

Neil

Neil

unread,
May 22, 2026, 2:03:17 AMMay 22
to scintilla-interest
Implemented scaling for Qt with the attached patch. It works, like John suggested, drawing into a full size bitmap then copying that to the window.

An image showing both the new implementation (left) and the old (right) at 150% scaling can be seen at https://www.scintilla.org/QtScale.png .

Just setting the painter scale to 1/scalingFactor should have worked but still produces seams. It's possible that scaling is being performed twice here.

This does some extra work since the entire Scintilla window is redrawn for every change so can be slow although it is mostly adequate. There is some commented-out code in Window::InvalidateRectangle that tried to redraw just the rectangle needed but, while this almost worked, there were occasional single pixel line debris when selecting with the mouse. It is likely that scaling will need to be applied in more places.

The code builds and works with Qt 6.10.2 on both Linux (Ubuntu 26.04 Wayland) and Windows 10. It will likely need #if to avoid new APIs for projects still with Qt 5.x.

There is an updated version of Haven that can test this at https://www.scintilla.org/HavenScale.zip . It uses a dark background as that makes seams more prominent when the system is in standard light 'daytime' mode.

Since this will need Qt version checks and may decrease performance, it is likely this will be delivered behind a preprocessor switch so downstream projects can opt into the change.

Neil

QtScale5.patch

Mitchell

unread,
May 22, 2026, 2:18:40 PMMay 22
to scintilla...@googlegroups.com
Hi Neil,

> On May 22, 2026, at 2:03 AM, Neil <scintil...@gmail.com> wrote:
>
> Implemented scaling for Qt with the attached patch. It works, like John suggested, drawing into a full size bitmap then copying that to the window.
>
> An image showing both the new implementation (left) and the old (right) at 150% scaling can be seen at https://www.scintilla.org/QtScale.png .

[snip]

I applied this patch to Qt 6 on macOS and I’m seeing some really weird effects. I’m on a Retina display, so that’s probably messing with the devicePixelRatio() computations.

See attached noscale.png and yesscale.png images. The arrows in the latter point to the weird things I’m seeing:
- hard to see indicators
- hard to see margin symbols
- too large autocompletion window

I looked at the documentation to try and find an option to set scaling, but I couldn’t find it. I assume the patch is supposed to detect and apply scaling via the devicePixelRatio() computations.

Cheers,
Mitchell

noscale.png
yesscale.png

Neil

unread,
May 23, 2026, 1:23:17 AMMay 23
to scintilla-interest
Mitchell:
 
I applied this patch to Qt 6 on macOS and I’m seeing some really weird effects.

Thanks for looking at the change. Some of these can be fixed and others are from decisions made when implementing scaling for Win32 and may require application additions or new APIs.
 
I’m on a Retina display, so that’s probably messing with the devicePixelRatio() computations.

Yes, macOS scales differently which makes it easy for macOS apps but may cause problems when Qt treats scaling more like Windows.

On Windows, scale factors between 100% and 200% are common - I mostly use a 4K monitor with Windows and Windows recommends 150%.

At 200% (as is common on macOS), it is reasonable to double all dimensions, making simple lines 2 pixels wide. At 150%, some people will prefer 1 pixel wide lines and some 2. Using floating point widths such as a 1.5 pixel wide lines will lead to 'fuzzy' features that are widely disliked. So I left most features with their original pixel widths with the intent of making more choices available so that applications and users can choose something that works for them and they can choose when to switch between feature sizes.

See attached noscale.png and yesscale.png images. The arrows in the latter point to the weird things I’m seeing:
- hard to see indicators

Most indicators do not scale. IndicatorStyle::Diagonal, in particular, tries to fit 3 pixel high underlines in the text descender area which is quite tight so may result in clipping.

With 'noscale.png' macOS Retina scaling, 3 pixels = 6 physical pixels which looks quite good. 'yesscale.png' is using 3 physical pixels so looks too faint. A new indicator (which I think should have a new name) could be implemented in various ways. The descender height could determine the height and spacing of the diagonal lines although that will decrease density. The stroke width could be made wider although it should probably remain an integer - a 1.5 pixel wide line here produces an less distinct blob.
 
- hard to see margin symbols

The margins are specified in physical pixels so the application should (if desired) scale the argument to SCI_SETMARGINWIDTHN. The reason Scintilla doesn't automatically scale these is that symbol margins are particularly sensitive to tweaking and I wanted applications to control exactly how wide margins are. SciTE provides a '$(scale)' function that may be used until more control is wanted.
 
- too large autocompletion window

The scale factor was applied twice to the font size and the size and position of the window so there is an update with an inverse scale in ListBoxImpl::SetFont and Window::SetPositionRelative then a compensating scale in ListBoxImpl::GetDesiredRect.

This is just part of the division between scaled graphics coordinates used by this patch and the need to coordinate with the window layer. Scaling could be handled more thoroughly with the factor flowing through the data structures although this would be more intrusive. The implementation here is trying to get this working with a small change to the edge of Scintilla, just in the Qt platform layer.

A QtScale7.patch that includes these changes is attached.
 
I looked at the documentation to try and find an option to set scaling, but I couldn’t find it. I assume the patch is supposed to detect and apply scaling via the devicePixelRatio() computations.

Yes, this is trying to be automatic, at least for basic uses. There could be an API either to set a scaling factor or just to control whether the scaling is enabled.

Also experimented with Qt 5.15.10 and the only symbol missing was QEvent::DevicePixelRatioChange so there is an #if to avoid that before it is available. All the devicePixelRatioF calls appear to work on Qt 5 which is great. The DevicePixelRatioChange  event was intercepted as otherwise Haven started up with 200% instead of 150% scaling - it appears that the accurate scaling factor is only discovered after the window is shown.

There is a further problem with current Ubuntu+Wayland in that the windows for autocompletion and calltips fail as they do not have an owning window as their transientParent. Wayland doesn't like applications showing top-level windows at arbitrary locations and wants these to be attached to owning windows. This has been a minor problem in the past with GTK but it mostly led to windows located poorly rather than failing. The relevant API setTransientParent can't be called after the window creation as creation has already failed and there may need to be some set up during the right stage of window construction / realization. This is orthogonal to scaling so may be something that one of the users of Qt on Linux can investigate.

Neil
QtScale7.patch

Mitchell

unread,
May 23, 2026, 7:45:22 PMMay 23
to scintilla...@googlegroups.com
Hi Neil,

> [snip]
>
> See attached noscale.png and yesscale.png images. The arrows in the latter point to the weird things I’m seeing:
> - hard to see indicators
>
> Most indicators do not scale. IndicatorStyle::Diagonal, in particular, tries to fit 3 pixel high underlines in the text descender area which is quite tight so may result in clipping.
>
> With 'noscale.png' macOS Retina scaling, 3 pixels = 6 physical pixels which looks quite good. 'yesscale.png' is using 3 physical pixels so looks too faint. A new indicator (which I think should have a new name) could be implemented in various ways. The descender height could determine the height and spacing of the diagonal lines although that will decrease density. The stroke width could be made wider although it should probably remain an integer - a 1.5 pixel wide line here produces an less distinct blob.

I like the indicators that I see without the patch. Having multiple new scale-specific indicators doesn’t sound ideal.

> - hard to see margin symbols
>
> The margins are specified in physical pixels so the application should (if desired) scale the argument to SCI_SETMARGINWIDTHN. The reason Scintilla doesn't automatically scale these is that symbol margins are particularly sensitive to tweaking and I wanted applications to control exactly how wide margins are. SciTE provides a '$(scale)' function that may be used until more control is wanted.

I increased my margin width using your new patch, but the markers remained the same, small size. Do I need to implement some sort of client-side scaling?

> - too large autocompletion window
>
> [snip]
>
> A QtScale7.patch that includes these changes is attached.

I confirm this is fixed.

I did run into a strange issue with a Scintilla view that is normally 1 line high is now 2 lines high. However, I set the height using the SCI_TEXTHEIGHT, so I suspect Scintilla is reporting a new scaled height. Either I have to divide by two, or Scintilla (or its Qt platform) needs to do another computation somewhere.

> I looked at the documentation to try and find an option to set scaling, but I couldn’t find it. I assume the patch is supposed to detect and apply scaling via the devicePixelRatio() computations.
>
> Yes, this is trying to be automatic, at least for basic uses. There could be an API either to set a scaling factor or just to control whether the scaling is enabled.

I would like some sort of control to disable scaling and keep the default drawing Scintilla Qt is doing on my Retina and 4K display (I assume macOS is doing 200% scaling for both). When I have time, I can enable scaling and then identify and report any issues I find, as I am now. Right now it feels like I’m going to run into a lot of small things over time rather than all at once. I’d be more comfortable with the fallback to disable and keep the current drawing.

Cheers,
Mitchell

Neil

unread,
May 24, 2026, 11:34:49 PM (14 days ago) May 24
to scintilla-interest
There were some more problems on current Wayland with the popups reporting a devicePixelRatioF of 2.0 when the system scale was 1.5 or 1.33. Its possible this is an initialization issue with windows not knowing an accurate scaling factor before they receive a set scale message. It was fixed by using the devicePixelRatioF of the main Scintilla window in the attached patch.

Mitchell:

I like the indicators that I see without the patch. Having multiple new scale-specific indicators doesn’t sound ideal.

It's more likely you will be able to replace Diagonal with a single new DiagonalProportionalToDescender (or similar name) that implements a particular style of scaling diagonals. If there are different opinions on the best technique to use then there could be more than one Diagonal*. A constraint here is that downstream Windows projects have been scaling for 6 years and shouldn't have their appearance modified in ways that they may not like or want.

I increased my margin width using your new patch, but the markers remained the same, small size. Do I need to implement some sort of client-side scaling?

It is likely you will have to perform some scaling yourself.

I did run into a strange issue with a Scintilla view that is normally 1 line high is now 2 lines high. However, I set the height using the SCI_TEXTHEIGHT, so I suspect Scintilla is reporting a new scaled height. Either I have to divide by two, or Scintilla (or its Qt platform) needs to do another computation somewhere.

I'm not sure. There are really two scales working in the code: graphics and windowing with window coordinates not being scaled.

I would like some sort of control to disable scaling and keep the default drawing Scintilla Qt is doing on my Retina and 4K display (I assume macOS is doing 200% scaling for both). When I have time, I can enable scaling and then identify and report any issues I find, as I am now. Right now it feels like I’m going to run into a lot of small things over time rather than all at once. I’d be more comfortable with the fallback to disable and keep the current drawing.

I have been working on this but scaling occurs in many places and the 'scaled' control property needs to be distributed and kept current.

Neil
QtScaleA.patch

Mitchell

unread,
May 25, 2026, 11:32:41 AM (13 days ago) May 25
to scintilla...@googlegroups.com
Hi Neil,

> On May 24, 2026, at 11:34 PM, Neil <scintil...@gmail.com> wrote:
>
> There were some more problems on current Wayland with the popups reporting a devicePixelRatioF of 2.0 when the system scale was 1.5 or 1.33. Its possible this is an initialization issue with windows not knowing an accurate scaling factor before they receive a set scale message. It was fixed by using the devicePixelRatioF of the main Scintilla window in the attached patch.
>
> Mitchell:
>
> I like the indicators that I see without the patch. Having multiple new scale-specific indicators doesn’t sound ideal.
>
> It's more likely you will be able to replace Diagonal with a single new DiagonalProportionalToDescender (or similar name) that implements a particular style of scaling diagonals. If there are different opinions on the best technique to use then there could be more than one Diagonal*.

That’s precisely what I’m concerned about. I use diagonal and squiggly indicators. They would each need their own scaled versions, possibly with more permutations. My application would have to pick an indicator based on detected scaling, etc. Right now, Qt already draws things correctly, even in my HiDPI Ubuntu 24.04 VM with 200% scaling.

> A constraint here is that downstream Windows projects have been scaling for 6 years and shouldn't have their appearance modified in ways that they may not like or want.

I think I could say my Mac project has been scaling for 6 years :) Or maybe I misunderstand your meaning.

> I increased my margin width using your new patch, but the markers remained the same, small size. Do I need to implement some sort of client-side scaling?
>
> It is likely you will have to perform some scaling yourself.

Okay, so another client-side branch based on whether or not the application is running on a HiDPI display.

> I did run into a strange issue with a Scintilla view that is normally 1 line high is now 2 lines high. However, I set the height using the SCI_TEXTHEIGHT, so I suspect Scintilla is reporting a new scaled height. Either I have to divide by two, or Scintilla (or its Qt platform) needs to do another computation somewhere.
>
> I'm not sure. There are really two scales working in the code: graphics and windowing with window coordinates not being scaled.

That’s what I was afraid of. Now I need to become an expert to know the difference between what units Scintilla’s APIs are reporting, and what units the Window toolkit is reporting.

> I would like some sort of control to disable scaling and keep the default drawing Scintilla Qt is doing on my Retina and 4K display (I assume macOS is doing 200% scaling for both). When I have time, I can enable scaling and then identify and report any issues I find, as I am now. Right now it feels like I’m going to run into a lot of small things over time rather than all at once. I’d be more comfortable with the fallback to disable and keep the current drawing.
>
> I have been working on this but scaling occurs in many places and the 'scaled' control property needs to be distributed and kept current.

I understand. It’s a hard issue with a non-zero maintenance burden.

Ultimately I will accept and adjust to whatever changes you make. I’m just offering my feedback now at this early stage for what it’s worth.

Cheers,
Mitchell

John Ehresman

unread,
May 25, 2026, 12:52:21 PM (13 days ago) May 25
to scintilla...@googlegroups.com
I’ve begun looking at this, though only with Haven so far. Haven does show the issues with margin width / stroke width — I mention it because I thought the INDIC_CONTAINER under the first two letters was a bug because it renders as a one device pixel black line that looks like a seam with the patched version of scintilla.

I plan to do more testing in the next few days.

Thanks,

John
> --
> 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 scintilla-inter...@googlegroups.com.
> To view this discussion visit https://groups.google.com/d/msgid/scintilla-interest/96031856-CB8D-45BE-9B32-3ADC515E511B%40foicica.com.

Neil Hodgson

unread,
May 28, 2026, 4:13:27 AM (10 days ago) May 28
to scintilla...@googlegroups.com
Mitchell:

> That’s precisely what I’m concerned about. I use diagonal and squiggly indicators. They would each need their own scaled versions,
> possibly with more permutations. My application would have to pick an indicator based on detected scaling, etc.

It's likely not possible to enable good fractional scaling without
some modifications to applications.

> Right now, Qt already draws things correctly, even in my HiDPI Ubuntu 24.04 VM with 200% scaling.

If only integral scaling was desired then there could be a simpler
implementation similar to macOS but that would be less capable than
Win32.

Neil

Neil Hodgson

unread,
May 28, 2026, 7:28:26 AM (10 days ago) May 28
to scintilla...@googlegroups.com
Attached is a patch that adds a ScintillaEditBase::SetScaled(bool
scaled) API that allows turning scaled mode on.

This change was difficult to make work so is probably fragile, not
minimal and may add new problems.

For Haven, I've been testing with placing the control in the "Wrap"
toggle menu item.

void MainWindow::on_actionWrap_triggered() {
Call(SCI_SETWRAPMODE, Call(SCI_GETWRAPMODE) ? SC_WRAP_NONE : SC_WRAP_WORD);
ui->blok->SetScaled(!ui->blok->Scaled());
}

Neil
QtScaleE.patch

Mitchell

unread,
May 29, 2026, 12:04:36 PM (9 days ago) May 29
to scintilla...@googlegroups.com
Hi Neil,
I have no idea why, but I’m getting scaled behavior by default on macOS, even if I manually call `SetScaled(false)` (which I shouldn’t have to, because it’s false by default).

```
auto view = new ScintillaEditBase;
view->SetScaled(false);
```

I reversed the patch, rebuilt, and I’m not seeing any more scaled behavior, so the patch is doing something, just not the expected thing.

Cheers,
Mitchell

Neil Hodgson

unread,
May 29, 2026, 9:44:14 PM (9 days ago) May 29
to scintilla...@googlegroups.com
Mitchell:

> I have no idea why, but I’m getting scaled behavior by default on macOS, even if I manually call `SetScaled(false)` (which I shouldn’t have to, because it’s false by default).

Yes, some of the effects are unexpected. Where above I said "difficult
to make work", part of that was that some changes made to disable
scaling were ineffective so scaling was reinstated. It's possible that
a Qt (or platform) internal scaling mode is set unexpectedly by
something like calling devicePixelRatioF.

A new issue I have noticed on Windows is that changing the system
scaling can cause the scroll bar to move a little sideways until the
window is resized. This may require a work-around like the application
resizing its widgets explicitly.

An updated Haven with a separate Scale menu item, margins that resize
on scale change event, and better dark-mode settings is available from
https://www.scintilla.org/HavenScale2.zip

Neil
Reply all
Reply to author
Forward
0 new messages