aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorMarkus Nißl <unknown>2022-11-26 22:28:13 +1100
committerMarkus Nißl <unknown>2022-11-26 22:28:13 +1100
commita179c1bd5f83c7b6c649fadbf98ffb2309e50adc (patch)
treeaab797c3e9b0abb491e6e5096aee13e8d8f8fce8
parentb9cef6c5e4baa41bfe1ff073d662153cb44880d7 (diff)
downloadscintilla-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.html4
-rw-r--r--scripts/HeaderOrder.txt1
-rw-r--r--win32/PlatWin.cxx52
-rw-r--r--win32/PlatWin.h1
-rw-r--r--win32/ScintillaWin.cxx37
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;