Menu

#2505 Blurry text in autocompletion lists with DirectWrite in a GDI scaled application

Bug
open
nobody
5
5 days ago
5 days ago
No

Since version 5.5.6, autocompletion lists are drawn using DirectWrite if the document is drawn with DirectWrite.

In a GDI scaled application using Scintilla with DirectWrite, text in autocompletion lists appears blurry. The following patch to ListBox.cxx fixes this.

The taken approach is similar to the one in #2344 DirectWrite rendering looks blurry with DPI unaware apps

--- scintilla5.6.1\win32\ListBox.cxx    2026-03-27 13:02:26.002174200 +0100
+++ myScintilla\win32\ListBox.cxx   2026-03-31 17:09:38.505640600 +0200
@@ -175,6 +175,10 @@ class ListBoxX : public ListBox {
    MouseWheelDelta wheelDelta;
    ListOptions options;
    DWORD frameStyle = WS_THICKFRAME;

+   float deviceScaleFactor = 1.f;
+   [[nodiscard]] int GetFirstIntegralMultipleDeviceScaleFactor() const noexcept {
+       return static_cast<int>(std::ceil(deviceScaleFactor));
+   }

    LBGraphics graphics;

@@ -265,6 +269,9 @@ void ListBoxX::Create(Window &parent_, i
        this);

    dpi = DpiForWindow(hwndParent);

+   if (technology != Technology::Default) {
+       deviceScaleFactor = Internal::GetDeviceScaleFactorWhenGdiScalingActive(hwndParent);
+   }
    POINT locationw = POINTFromPoint(location);
    ::MapWindowPoints(hwndParent, {}, &locationw, 1);
    location = PointFromPOINT(locationw);
@@ -423,7 +430,8 @@ void ListBoxX::Draw(DRAWITEMSTRUCT *pDra
 #endif

    const PRectangle rcItemBase = PRectangleFromRECT(pDrawItem->rcItem);

-   const PRectangle rcItem(0, 0, rcItemBase.Width(), rcItemBase.Height());
+   const int integralDeviceScaleFactor = GetFirstIntegralMultipleDeviceScaleFactor();
+   const PRectangle rcItem(0, 0, rcItemBase.Width() * integralDeviceScaleFactor, rcItemBase.Height() * integralDeviceScaleFactor);
    PRectangle rcBox = rcItem;
    rcBox.left += TextOffset();
    ColourRGBA colourFore;
@@ -458,6 +466,7 @@ void ListBoxX::Draw(DRAWITEMSTRUCT *pDra
        PRectangle rcImage = rcItem;
        rcImage.left = left;
        rcImage.right = rcImage.left + images.GetWidth();
+       rcImage.bottom = rcImage.top + rcItemBase.Height();
        graphics.pixmapLine->DrawRGBAImage(rcImage,
            pimage->GetWidth(), pimage->GetHeight(), pimage->Pixels());
    }
@@ -473,7 +482,11 @@ void ListBoxX::Draw(DRAWITEMSTRUCT *pDra

    // Blit from hMemDC to hDC
    const SIZE extent = SizeOfRect(pDrawItem->rcItem);

-   ::BitBlt(pDrawItem->hDC, pDrawItem->rcItem.left, pDrawItem->rcItem.top, extent.cx, extent.cy, graphics.bm.DC(), 0, 0, SRCCOPY);
+   if (integralDeviceScaleFactor == 1) {
+       ::BitBlt(pDrawItem->hDC, pDrawItem->rcItem.left, pDrawItem->rcItem.top, extent.cx, extent.cy, graphics.bm.DC(), 0, 0, SRCCOPY);
+   } else {
+       ::StretchBlt(pDrawItem->hDC, pDrawItem->rcItem.left, pDrawItem->rcItem.top, extent.cx, extent.cy, graphics.bm.DC(), 0, 0, extent.cx * integralDeviceScaleFactor, extent.cy * integralDeviceScaleFactor, SRCCOPY);
+   }
 }

 void ListBoxX::AppendListItem(const char *text, const char *numword) {
@@ -748,7 +761,8 @@ void ListBoxX::CentreItem(int n) {
 }

 void ListBoxX::AllocateBitMap() {

-   const SIZE extent { GetClientExtent().x, ItemHeight() };
+   const int integralDeviceScaleFactor = GetFirstIntegralMultipleDeviceScaleFactor();
+   const SIZE extent { GetClientExtent().x * integralDeviceScaleFactor, ItemHeight() * integralDeviceScaleFactor };

    graphics.bm.Create({}, extent.cx, -extent.cy, nullptr);
    if (!graphics.bm) {
@@ -765,9 +779,12 @@ void ListBoxX::AllocateBitMap() {
            return;
        }


+       const FLOAT dpiTarget = dpiDefault * static_cast<float>(integralDeviceScaleFactor);
+
        const D2D1_RENDER_TARGET_PROPERTIES drtp = D2D1::RenderTargetProperties(
            D2D1_RENDER_TARGET_TYPE_DEFAULT,
-           { DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED });
+           { DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED },
+           dpiTarget, dpiTarget);

        HRESULT hr = CreateDCRenderTarget(&drtp, graphics.pBMDCTarget);
        if (FAILED(hr) || !graphics.pBMDCTarget) {

Discussion


Log in to post a comment.

MongoDB Logo MongoDB