From 9e5c8a802700f3fef6c1fda6d3b375e3e21e42cc Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 26 Mar 2022 01:38:59 +0100 Subject: [PATCH] Respect bitmap content scale factor in wxMSW wxMemoryDC Apply it manually because MSW doesn't do it automatically for us and also adjust the font size in wxMemoryDC as the base class version only does it for the device contexts associated with a window, but we also need to do it when using a wxMemoryDC for a bitmap using scale factor different from that of the main display. As the result of these changes, contents drawn on wxMemoryDC, both directly via its own methods, or via wxGraphicsContext (using either GDI+ or Direct2D) created from it, it appears the same as in wxWindowDC (e.g. wxPaintDC) created for a window using the same scale. Closes #22130. Closes #22234. --- include/wx/msw/dcmemory.h | 2 ++ samples/drawing/drawing.cpp | 3 ++- src/msw/dc.cpp | 2 +- src/msw/dcmemory.cpp | 19 +++++++++++++++++++ src/msw/graphics.cpp | 12 ++++++++++-- src/msw/graphicsd2d.cpp | 8 +++++--- 6 files changed, 39 insertions(+), 7 deletions(-) diff --git a/include/wx/msw/dcmemory.h b/include/wx/msw/dcmemory.h index f7e4282c5b..7449e27885 100644 --- a/include/wx/msw/dcmemory.h +++ b/include/wx/msw/dcmemory.h @@ -22,6 +22,8 @@ public: wxMemoryDCImpl( wxMemoryDC *owner, wxDC *dc ); // Create compatible DC // override some base class virtuals + virtual void SetFont(const wxFont& font) wxOVERRIDE; + virtual void DoDrawRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height) wxOVERRIDE; virtual void DoGetSize(int* width, int* height) const wxOVERRIDE; virtual void DoSelect(const wxBitmap& bitmap) wxOVERRIDE; diff --git a/samples/drawing/drawing.cpp b/samples/drawing/drawing.cpp index 55e8e62c52..717f880560 100644 --- a/samples/drawing/drawing.cpp +++ b/samples/drawing/drawing.cpp @@ -2535,7 +2535,8 @@ void MyFrame::OnSave(wxCommandEvent& WXUNUSED(event)) else #endif // wxUSE_POSTSCRIPT { - wxBitmap bmp(width, height); + wxBitmap bmp; + bmp.CreateWithDIPSize(wxSize(width, height), GetDPIScaleFactor()); wxMemoryDC mdc(bmp); mdc.SetBackground(*wxWHITE_BRUSH); mdc.Clear(); diff --git a/src/msw/dc.cpp b/src/msw/dc.cpp index 35ce2d0472..0cc9531e2b 100644 --- a/src/msw/dc.cpp +++ b/src/msw/dc.cpp @@ -2648,7 +2648,7 @@ wxSize wxMSWDCImpl::GetPPI() const if ( !ppi.x || !ppi.y ) { - ppi = wxGetDPIofHDC(GetHdc()); + ppi = wxGetDPIofHDC(GetHdc())*GetContentScaleFactor(); } return ppi; diff --git a/src/msw/dcmemory.cpp b/src/msw/dcmemory.cpp index bdcd97af46..9d7c52b531 100644 --- a/src/msw/dcmemory.cpp +++ b/src/msw/dcmemory.cpp @@ -28,6 +28,8 @@ #include "wx/log.h" #endif +#include "wx/display.h" + #include "wx/msw/private.h" // ---------------------------------------------------------------------------- @@ -131,6 +133,23 @@ void wxMemoryDCImpl::DoSelect( const wxBitmap& bitmap ) { m_oldBitmap = hBmp; } + + // Remember content scale factor used by the bitmap: we don't use it + // ourselves, but this can be needed later for creating fonts of the + // correct size. + m_contentScaleFactor = bitmap.GetScaleFactor(); + + // The font may need to be adjusted for the new scale factor. + SetFont(GetFont()); +} + +void wxMemoryDCImpl::SetFont(const wxFont& font) +{ + // We need to adjust the font size by the ratio between the scale factor we + // use and the default/global scale factor used when creating fonts. + wxFont scaledFont = font; + scaledFont.WXAdjustToPPI(wxDisplay::GetStdPPI()*m_contentScaleFactor); + wxMSWDCImpl::SetFont(scaledFont); } void wxMemoryDCImpl::DoGetSize(int *width, int *height) const diff --git a/src/msw/graphics.cpp b/src/msw/graphics.cpp index 21782259c7..c03fca4a1a 100644 --- a/src/msw/graphics.cpp +++ b/src/msw/graphics.cpp @@ -2503,9 +2503,9 @@ void wxGDIPlusContext::GetDPI(wxDouble* dpiX, wxDouble* dpiY) const else { if ( dpiX ) - *dpiX = GetGraphics()->GetDpiX(); + *dpiX = GetGraphics()->GetDpiX()*GetContentScaleFactor(); if ( dpiY ) - *dpiY = GetGraphics()->GetDpiY(); + *dpiY = GetGraphics()->GetDpiY()*GetContentScaleFactor(); } } @@ -2730,6 +2730,14 @@ wxGraphicsContext * wxGDIPlusRenderer::CreateContext( const wxMemoryDC& dc) wxGDIPlusContext* context = new wxGDIPlusContext(this, dc); context->EnableOffset(true); + + // GDI+ uses the default system DPI, so we don't need to do anything if the + // scale factor of the associated bitmap is already the same, but we do + // need to scale it correctly if it is different from the scale factor for + // the default DPI. To get the latter, we would normally use a screen HDC + // but we already have a memory HDC at hand, so we can just use it instead. + const int defDPI = wxGetDPIofHDC(GetHdcOf(dc)).y; + context->SetContentScaleFactor(dc.GetContentScaleFactor() * 96.0 / defDPI); return context; } diff --git a/src/msw/graphicsd2d.cpp b/src/msw/graphicsd2d.cpp index 49acd404c1..c195148fe1 100644 --- a/src/msw/graphicsd2d.cpp +++ b/src/msw/graphicsd2d.cpp @@ -4965,9 +4965,9 @@ void wxD2DContext::GetDPI(wxDouble* dpiX, wxDouble* dpiY) const GetRenderTarget()->GetDpi(&x, &y); if ( dpiX ) - *dpiX = x; + *dpiX = x*GetContentScaleFactor(); if ( dpiY ) - *dpiY = y; + *dpiY = y*GetContentScaleFactor(); } } @@ -5131,8 +5131,10 @@ wxGraphicsContext* wxD2DRenderer::CreateContext(const wxMemoryDC& dc) wxBitmap bmp = dc.GetSelectedBitmap(); wxASSERT_MSG( bmp.IsOk(), wxS("Should select a bitmap before creating wxGraphicsContext") ); - return new wxD2DContext(this, m_direct2dFactory, dc.GetHDC(), &dc, + wxD2DContext* d2d = new wxD2DContext(this, m_direct2dFactory, dc.GetHDC(), &dc, bmp.HasAlpha() ? D2D1_ALPHA_MODE_PREMULTIPLIED : D2D1_ALPHA_MODE_IGNORE); + d2d->SetContentScaleFactor(dc.GetContentScaleFactor()); + return d2d; } #if wxUSE_PRINTING_ARCHITECTURE