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;  | 
