diff options
author | Markus Nißl <unknown> | 2022-11-26 22:28:13 +1100 |
---|---|---|
committer | Markus Nißl <unknown> | 2022-11-26 22:28:13 +1100 |
commit | a179c1bd5f83c7b6c649fadbf98ffb2309e50adc (patch) | |
tree | aab797c3e9b0abb491e6e5096aee13e8d8f8fce8 | |
parent | b9cef6c5e4baa41bfe1ff073d662153cb44880d7 (diff) | |
download | scintilla-mirror-a179c1bd5f83c7b6c649fadbf98ffb2309e50adc.tar.gz |
Bug [#2344]. Avoid blurry display with DirectWrite in GDI scaling mode.
https://sourceforge.net/p/scintilla/code/merge-requests/28/
-rw-r--r-- | doc/ScintillaHistory.html | 4 | ||||
-rw-r--r-- | scripts/HeaderOrder.txt | 1 | ||||
-rw-r--r-- | win32/PlatWin.cxx | 52 | ||||
-rw-r--r-- | win32/PlatWin.h | 1 | ||||
-rw-r--r-- | win32/ScintillaWin.cxx | 37 |
5 files changed, 77 insertions, 18 deletions
diff --git a/doc/ScintillaHistory.html b/doc/ScintillaHistory.html index d3787329c..2f9cf9d82 100644 --- a/doc/ScintillaHistory.html +++ b/doc/ScintillaHistory.html @@ -602,6 +602,10 @@ <a href="https://sourceforge.net/p/scintilla/feature-requests/1459/">Feature #1459</a>. </li> <li> + On Win32, avoid blurry display with DirectWrite in GDI scaling mode. + <a href="https://sourceforge.net/p/scintilla/bugs/2344/">Bug #2344</a>. + </li> + <li> On Win32, use the top-level window to find the monitor for DirectWrite rendering parameters. Temporarily switch DPI awareness to find correct monitor in GDI scaling mode. <a href="https://sourceforge.net/p/scintilla/bugs/2344/">Bug #2344</a>. diff --git a/scripts/HeaderOrder.txt b/scripts/HeaderOrder.txt index b47057e7b..c17d1897b 100644 --- a/scripts/HeaderOrder.txt +++ b/scripts/HeaderOrder.txt @@ -76,6 +76,7 @@ #include <commctrl.h> #include <richedit.h> #include <windowsx.h> +#include <shellscalingapi.h> #include <zmouse.h> #include <ole2.h> #include <d2d1.h> diff --git a/win32/PlatWin.cxx b/win32/PlatWin.cxx index c97b9283b..b52aa477a 100644 --- a/win32/PlatWin.cxx +++ b/win32/PlatWin.cxx @@ -36,6 +36,7 @@ #include <commctrl.h> #include <richedit.h> #include <windowsx.h> +#include <shellscalingapi.h> #if !defined(DISABLE_D2D) #define USE_D2D 1 @@ -157,6 +158,15 @@ GetSystemMetricsForDpiSig fnGetSystemMetricsForDpi = nullptr; using AdjustWindowRectExForDpiSig = BOOL(WINAPI *)(LPRECT lpRect, DWORD dwStyle, BOOL bMenu, DWORD dwExStyle, UINT dpi); AdjustWindowRectExForDpiSig fnAdjustWindowRectExForDpi = nullptr; +using AreDpiAwarenessContextsEqualSig = BOOL(WINAPI *)(DPI_AWARENESS_CONTEXT, DPI_AWARENESS_CONTEXT); +AreDpiAwarenessContextsEqualSig fnAreDpiAwarenessContextsEqual = nullptr; + +using GetWindowDpiAwarenessContextSig = DPI_AWARENESS_CONTEXT(WINAPI *)(HWND); +GetWindowDpiAwarenessContextSig fnGetWindowDpiAwarenessContext = nullptr; + +using GetScaleFactorForMonitorSig = HRESULT(WINAPI *)(HMONITOR, DEVICE_SCALE_FACTOR *); +GetScaleFactorForMonitorSig fnGetScaleFactorForMonitor = nullptr; + using SetThreadDpiAwarenessContextSig = DPI_AWARENESS_CONTEXT(WINAPI *)(DPI_AWARENESS_CONTEXT); SetThreadDpiAwarenessContextSig fnSetThreadDpiAwarenessContext = nullptr; @@ -177,11 +187,13 @@ void LoadDpiForWindow() noexcept { ::DeleteDC(hdcMeasure); } - if (!fnGetDpiForWindow) { - hDLLShcore = ::LoadLibraryExW(L"shcore.dll", {}, LOAD_LIBRARY_SEARCH_SYSTEM32); - if (hDLLShcore) { - fnGetDpiForMonitor = DLLFunction<GetDpiForMonitorSig>(hDLLShcore, "GetDpiForMonitor"); - } + fnGetWindowDpiAwarenessContext = DLLFunction<GetWindowDpiAwarenessContextSig>(user32, "GetWindowDpiAwarenessContext"); + fnAreDpiAwarenessContextsEqual = DLLFunction<AreDpiAwarenessContextsEqualSig>(user32, "AreDpiAwarenessContextsEqual"); + + hDLLShcore = ::LoadLibraryExW(L"shcore.dll", {}, LOAD_LIBRARY_SEARCH_SYSTEM32); + if (hDLLShcore) { + fnGetScaleFactorForMonitor = DLLFunction<GetScaleFactorForMonitorSig>(hDLLShcore, "GetScaleFactorForMonitor"); + fnGetDpiForMonitor = DLLFunction<GetDpiForMonitorSig>(hDLLShcore, "GetDpiForMonitor"); } } @@ -381,6 +393,20 @@ HMONITOR MonitorFromWindow(HWND hWnd) noexcept { return monitor; } +int GetDeviceScaleFactorWhenGdiScalingActive(HWND hWnd) noexcept { + if (fnAreDpiAwarenessContextsEqual) { + PLATFORM_ASSERT(fnGetWindowDpiAwarenessContext && fnGetScaleFactorForMonitor); + if (fnAreDpiAwarenessContextsEqual(DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED, fnGetWindowDpiAwarenessContext(hWnd))) { + const HWND hRootWnd = ::GetAncestor(hWnd, GA_ROOT); // Scale factor applies to entire (root) window. + const HMONITOR hMonitor = MonitorFromWindow(hRootWnd, MONITOR_DEFAULTTONEAREST); + DEVICE_SCALE_FACTOR deviceScaleFactor; + if (S_OK == fnGetScaleFactorForMonitor(hMonitor, &deviceScaleFactor)) + return (static_cast<int>(deviceScaleFactor) + 99) / 100; // increase to first integral multiple of 1 + } + } + return 1; +} + std::shared_ptr<Font> Font::Allocate(const FontParameters &fp) { #if defined(USE_D2D) if (fp.technology != Technology::Default) { @@ -1310,11 +1336,13 @@ class SurfaceD2D : public Surface, public ISetRenderingParams { static constexpr FontQuality invalidFontQuality = FontQuality::QualityMask; FontQuality fontQuality = invalidFontQuality; int logPixelsY = USER_DEFAULT_SCREEN_DPI; + int deviceScaleFactor = 1; std::shared_ptr<RenderingParams> renderingParams; void Clear() noexcept; void SetFontQuality(FontQuality extraFontFlag); HRESULT GetBitmap(ID2D1Bitmap **ppBitmap); + void SetDeviceScaleFactor(const ID2D1RenderTarget *const pRenderTarget) noexcept; public: SurfaceD2D() noexcept; @@ -1404,6 +1432,7 @@ SurfaceD2D::SurfaceD2D(ID2D1RenderTarget *pRenderTargetCompatible, int width, in &desiredSize, nullptr, &desiredFormat, D2D1_COMPATIBLE_RENDER_TARGET_OPTIONS_NONE, &pBitmapRenderTarget); if (SUCCEEDED(hr)) { pRenderTarget = pBitmapRenderTarget; + SetDeviceScaleFactor(pRenderTarget); pRenderTarget->BeginDraw(); ownRenderTarget = true; } @@ -1462,6 +1491,7 @@ void SurfaceD2D::Init(SurfaceID sid, WindowID wid) { Release(); SetScale(wid); pRenderTarget = static_cast<ID2D1RenderTarget *>(sid); + SetDeviceScaleFactor(pRenderTarget); } std::unique_ptr<Surface> SurfaceD2D::AllocatePixMap(int width, int height) { @@ -1510,9 +1540,15 @@ int SurfaceD2D::LogPixelsY() { return logPixelsY; } +void SurfaceD2D::SetDeviceScaleFactor(const ID2D1RenderTarget *const pD2D1RenderTarget) noexcept { + FLOAT dpiX = 0.f; + FLOAT dpiY = 0.f; + pD2D1RenderTarget->GetDpi(&dpiX, &dpiY); + deviceScaleFactor = static_cast<int>(dpiX / 96.f); +} + int SurfaceD2D::PixelDivisions() { - // Win32 uses device pixels. - return 1; + return deviceScaleFactor; } int SurfaceD2D::DeviceHeightFont(int points) { @@ -1644,7 +1680,7 @@ void SurfaceD2D::FillRectangle(PRectangle rc, Fill fill) { } void SurfaceD2D::FillRectangleAligned(PRectangle rc, Fill fill) { - FillRectangle(PixelAlign(rc, 1), fill); + FillRectangle(PixelAlign(rc, PixelDivisions()), fill); } void SurfaceD2D::FillRectangle(PRectangle rc, Surface &surfacePattern) { diff --git a/win32/PlatWin.h b/win32/PlatWin.h index 8261aeb2d..aa16e9f89 100644 --- a/win32/PlatWin.h +++ b/win32/PlatWin.h @@ -46,6 +46,7 @@ void SetWindowPointer(HWND hWnd, void *ptr) noexcept; HMONITOR MonitorFromWindow(HWND hWnd) noexcept; UINT DpiForWindow(WindowID wid) noexcept; +int GetDeviceScaleFactorWhenGdiScalingActive(HWND hWnd) noexcept; int SystemMetricsForDpi(int nIndex, UINT dpi) noexcept; diff --git a/win32/ScintillaWin.cxx b/win32/ScintillaWin.cxx index d3c1b87a5..efbe1f000 100644 --- a/win32/ScintillaWin.cxx +++ b/win32/ScintillaWin.cxx @@ -324,6 +324,8 @@ class ScintillaWin : static ATOM scintillaClassAtom; static ATOM callClassAtom; + int deviceScaleFactor = 1; + #if defined(USE_D2D) ID2D1RenderTarget *pRenderTarget; bool renderTargetValid; @@ -626,11 +628,23 @@ bool ScintillaWin::UpdateRenderingParams(bool force) noexcept { } hCurrentMonitor = monitor; + deviceScaleFactor = Internal::GetDeviceScaleFactorWhenGdiScalingActive(hRootWnd); renderingParams->defaultRenderingParams.reset(monitorRenderingParams); renderingParams->customRenderingParams.reset(customClearTypeRenderingParams); return true; } +namespace { + +D2D1_SIZE_U GetSizeUFromRect(const RECT &rc, const int scaleFactor) noexcept { + const long width = rc.right - rc.left; + const long height = rc.bottom - rc.top; + const UINT32 scaledWidth = width * scaleFactor; + const UINT32 scaledHeight = height * scaleFactor; + return D2D1::SizeU(scaledWidth, scaledHeight); +} + +} void ScintillaWin::EnsureRenderTarget(HDC hdc) { if (!renderTargetValid) { @@ -642,19 +656,15 @@ void ScintillaWin::EnsureRenderTarget(HDC hdc) { RECT rc; ::GetClientRect(hw, &rc); - const D2D1_SIZE_U size = D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top); - // Create a Direct2D render target. D2D1_RENDER_TARGET_PROPERTIES drtp {}; drtp.type = D2D1_RENDER_TARGET_TYPE_DEFAULT; - drtp.pixelFormat.format = DXGI_FORMAT_UNKNOWN; - drtp.pixelFormat.alphaMode = D2D1_ALPHA_MODE_UNKNOWN; - drtp.dpiX = 96.0; - drtp.dpiY = 96.0; drtp.usage = D2D1_RENDER_TARGET_USAGE_NONE; drtp.minLevel = D2D1_FEATURE_LEVEL_DEFAULT; if (technology == Technology::DirectWriteDC) { + drtp.dpiX = 96.f; + drtp.dpiY = 96.f; // Explicit pixel format needed. drtp.pixelFormat = D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE); @@ -669,9 +679,14 @@ void ScintillaWin::EnsureRenderTarget(HDC hdc) { } } else { + drtp.dpiX = 96.f * deviceScaleFactor; + drtp.dpiY = 96.f * deviceScaleFactor; + drtp.pixelFormat = D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, + D2D1_ALPHA_MODE_UNKNOWN); + D2D1_HWND_RENDER_TARGET_PROPERTIES dhrtp {}; dhrtp.hwnd = hw; - dhrtp.pixelSize = size; + dhrtp.pixelSize = ::GetSizeUFromRect(rc, deviceScaleFactor); dhrtp.presentOptions = (technology == Technology::DirectWriteRetain) ? D2D1_PRESENT_OPTIONS_RETAIN_CONTENTS : D2D1_PRESENT_OPTIONS_NONE; @@ -3594,10 +3609,12 @@ LRESULT PASCAL ScintillaWin::CTWndProc( surfaceWindow->Init(ps.hdc, hWnd); } else { #if defined(USE_D2D) + const int scaleFactor = sciThis->deviceScaleFactor; + // Create a Direct2D render target. D2D1_HWND_RENDER_TARGET_PROPERTIES dhrtp {}; dhrtp.hwnd = hWnd; - dhrtp.pixelSize = D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top); + dhrtp.pixelSize = ::GetSizeUFromRect(rc, scaleFactor); dhrtp.presentOptions = (sciThis->technology == Technology::DirectWriteRetain) ? D2D1_PRESENT_OPTIONS_RETAIN_CONTENTS : D2D1_PRESENT_OPTIONS_NONE; @@ -3605,8 +3622,8 @@ LRESULT PASCAL ScintillaWin::CTWndProc( drtp.type = D2D1_RENDER_TARGET_TYPE_DEFAULT; drtp.pixelFormat.format = DXGI_FORMAT_UNKNOWN; drtp.pixelFormat.alphaMode = D2D1_ALPHA_MODE_UNKNOWN; - drtp.dpiX = 96.0; - drtp.dpiY = 96.0; + drtp.dpiX = 96.f * scaleFactor; + drtp.dpiY = 96.f * scaleFactor; drtp.usage = D2D1_RENDER_TARGET_USAGE_NONE; drtp.minLevel = D2D1_FEATURE_LEVEL_DEFAULT; |