Merge branch 'msw-font-dpi'

Various wxFont-related fixes and refactorings in preparation for adding
per-monitor DPI support.

Closes https://github.com/wxWidgets/wxWidgets/pull/1408
This commit is contained in:
Vadim Zeitlin
2019-07-12 18:53:24 +02:00
12 changed files with 83 additions and 78 deletions

View File

@@ -118,7 +118,20 @@ public:
// set the XFLD
void SetXFontName(const wxString& xFontName);
#elif defined(__WXMSW__)
wxNativeFontInfo(const LOGFONT& lf_) : lf(lf_), pointSize(0.0f) { }
wxNativeFontInfo(const LOGFONT& lf_);
// MSW-specific: get the height value in pixels using LOGFONT convention
// (i.e. negative) corresponding to the given size in points and DPI.
static int GetLogFontHeightAtPPI(float size, int ppi)
{
return -wxRound(size * ppi / 72.0);
}
// And the same thing for the size of this font.
int GetLogFontHeightAtPPI(int ppi) const
{
return GetLogFontHeightAtPPI(pointSize, ppi);
}
LOGFONT lf;

View File

@@ -961,10 +961,14 @@ extern const wxCursor *wxGetGlobalCursor(); // from msw/cursor.cpp
WXDLLIMPEXP_CORE void wxGetCursorPosMSW(POINT* pt);
WXDLLIMPEXP_CORE void wxGetCharSize(WXHWND wnd, int *x, int *y, const wxFont& the_font);
WXDLLIMPEXP_CORE void wxFillLogFont(LOGFONT *logFont, const wxFont *font);
WXDLLIMPEXP_CORE wxFont wxCreateFontFromLogFont(const LOGFONT *logFont);
WXDLLIMPEXP_CORE wxFontEncoding wxGetFontEncFromCharSet(int charset);
inline void wxSetWindowFont(HWND hwnd, const wxFont& font)
{
::SendMessage(hwnd, WM_SETFONT,
(WPARAM)GetHfontOf(font), MAKELPARAM(TRUE, 0));
}
WXDLLIMPEXP_CORE void wxSliderEvent(WXHWND control, WXWORD wParam, WXWORD pos);
WXDLLIMPEXP_CORE void wxScrollBarEvent(WXHWND hbar, WXWORD wParam, WXWORD pos);

View File

@@ -113,14 +113,11 @@ public:
// set font for all windows
void SetFont(const wxFont& font)
{
HFONT hfont = GetHfontOf(font);
wxCHECK_RET( hfont, wxT("invalid font") );
for ( size_t n = 0; n < m_count; n++ )
{
if ( m_hwnds[n] )
{
::SendMessage(m_hwnds[n], WM_SETFONT, (WPARAM)hfont, 0);
wxSetWindowFont(m_hwnds[n], font);
// otherwise the window might not be redrawn correctly
::InvalidateRect(m_hwnds[n], NULL, FALSE /* don't erase bg */);

View File

@@ -152,6 +152,16 @@ public:
return m_hFont != 0;
}
int GetLogFontHeight() const
{
return m_nativeFontInfo.lf.lfHeight;
}
int GetLogFontHeightAtPPI(int ppi) const
{
return m_nativeFontInfo.GetLogFontHeightAtPPI(ppi);
}
// ... and setters: notice that all of them invalidate the currently
// allocated HFONT, if any, so that the next call to GetHFONT() recreates a
// new one
@@ -223,6 +233,13 @@ public:
m_nativeFontInfo.SetEncoding(encoding);
}
void SetLogFontHeight(int height)
{
Free();
m_nativeFontInfo.lf.lfHeight = height;
}
const wxNativeFontInfo& GetNativeFontInfo() const
{
// we need to create the font now to get the corresponding LOGFONT if
@@ -385,6 +402,15 @@ void wxFontRefData::Free()
// wxNativeFontInfo
// ----------------------------------------------------------------------------
wxNativeFontInfo::wxNativeFontInfo(const LOGFONT& lf_)
: lf(lf_)
{
// Determine the size in points using the primary screen DPI as we don't
// have anything else here.
const float ppi = ::GetDeviceCaps(ScreenHDC(), LOGPIXELSY);
pointSize = 72.0f * abs(lf.lfHeight) / ppi;
}
void wxNativeFontInfo::Init()
{
wxZeroMemory(lf);
@@ -402,14 +428,7 @@ void wxNativeFontInfo::Init()
float wxNativeFontInfo::GetFractionalPointSize() const
{
if ( pointSize != 0.0f )
return pointSize;
// FIXME: using the screen here results in incorrect font size calculation
// for printing!
const int ppInch = ::GetDeviceCaps(ScreenHDC(), LOGPIXELSY);
return (72.0*abs(lf.lfHeight)) / (double) ppInch;
}
wxSize wxNativeFontInfo::GetPixelSize() const
@@ -490,17 +509,14 @@ wxFontEncoding wxNativeFontInfo::GetEncoding() const
return wxGetFontEncFromCharSet(lf.lfCharSet);
}
void wxNativeFontInfo::SetFractionalPointSize(float pointsize)
void wxNativeFontInfo::SetFractionalPointSize(float pointSizeNew)
{
// Store it to be able to return it from GetFractionalPointSize() later
// exactly.
pointSize = pointsize;
// We don't have the correct DPI to use here, so use that of the
// primary screen.
const int ppi = ::GetDeviceCaps(ScreenHDC(), LOGPIXELSY);
lf.lfHeight = GetLogFontHeightAtPPI(pointSizeNew, ppi);
// FIXME: using the screen here results in incorrect font size calculation
// for printing!
const int ppInch = ::GetDeviceCaps(ScreenHDC(), LOGPIXELSY);
lf.lfHeight = -wxRound(pointsize*((double)ppInch)/72.0);
pointSize = pointSizeNew;
}
void wxNativeFontInfo::SetPixelSize(const wxSize& pixelSize)
@@ -516,6 +532,11 @@ void wxNativeFontInfo::SetPixelSize(const wxSize& pixelSize)
// versions by passing a negative value explicitly itself.
lf.lfHeight = -abs(pixelSize.GetHeight());
lf.lfWidth = pixelSize.GetWidth();
// We don't have the right DPI to use here neither, but we need to update
// the point size too, so fall back to the default.
const float ppi = ::GetDeviceCaps(ScreenHDC(), LOGPIXELSY);
pointSize = 72.0f * pixelSize.GetHeight() / ppi;
}
void wxNativeFontInfo::SetStyle(wxFontStyle style)
@@ -855,7 +876,6 @@ void wxFont::SetFractionalPointSize(float pointSize)
{
AllocExclusive();
M_FONTDATA->Free();
M_FONTDATA->SetFractionalPointSize(pointSize);
}

View File

@@ -36,6 +36,8 @@
#include "wx/math.h"
#endif
#include "wx/fontutil.h"
#include <stdlib.h>
#include <string.h>
@@ -118,7 +120,7 @@ int wxFontDialog::ShowModal()
if ( m_fontData.m_initialFont.IsOk() )
{
flags |= CF_INITTOLOGFONTSTRUCT;
wxFillLogFont(&logFont, &m_fontData.m_initialFont);
logFont = m_fontData.m_initialFont.GetNativeFontInfo()->lf;
}
if ( m_fontData.m_fontColour.IsOk() )
@@ -150,7 +152,7 @@ int wxFontDialog::ShowModal()
if ( ChooseFont(&chooseFontStruct) != 0 )
{
wxRGBToColour(m_fontData.m_fontColour, chooseFontStruct.rgbColors);
m_fontData.m_chosenFont = wxCreateFontFromLogFont(&logFont);
m_fontData.m_chosenFont = wxFont(wxNativeFontInfo(logFont));
m_fontData.EncodingInfo().facename = logFont.lfFaceName;
m_fontData.EncodingInfo().charset = logFont.lfCharSet;

View File

@@ -264,35 +264,3 @@ wxFontEncoding wxGetFontEncFromCharSet(int cs)
return fontEncoding;
}
// ----------------------------------------------------------------------------
// wxFont <-> LOGFONT conversion
// ----------------------------------------------------------------------------
void wxFillLogFont(LOGFONT *logFont, const wxFont *font)
{
wxNativeFontInfo fi;
// maybe we already have LOGFONT for this font?
const wxNativeFontInfo *pFI = font->GetNativeFontInfo();
if ( !pFI )
{
// use wxNativeFontInfo methods to build a LOGFONT for this font
fi.InitFromFont(*font);
pFI = &fi;
}
// transfer all the data to LOGFONT
*logFont = pFI->lf;
}
wxFont wxCreateFontFromLogFont(const LOGFONT *logFont)
{
wxNativeFontInfo info;
info.lf = *logFont;
return wxFont(info);
}

View File

@@ -620,8 +620,7 @@ bool wxListCtrl::SetHeaderAttr(const wxItemAttr& attr)
// We need to tell the header about its new font to let it compute
// its new height.
::SendMessage(hwndHdr, WM_SETFONT,
(WPARAM)GetHfontOf(font), MAKELPARAM(TRUE, 0));
wxSetWindowFont(hwndHdr, font);
}
// Refreshing the listview makes it notice the change in height of its

View File

@@ -552,7 +552,8 @@ int wxRendererMSW::GetHeaderButtonHeight(wxWindow * win)
font = win->GetFont();
if ( !font.IsOk() )
wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
::SendMessage(hwndHeader, WM_SETFONT, (WPARAM)GetHfontOf(font), 0);
wxSetWindowFont(hwndHeader, font);
// initialize the struct filled with the values by Header_Layout()
RECT parentRect = { 0, 0, 100, 100 };

View File

@@ -345,7 +345,7 @@ extern wxFont wxGetCCDefaultFont()
0
) )
{
return wxFont(wxCreateFontFromLogFont(&lf));
return wxFont(lf);
}
else
{

View File

@@ -564,8 +564,7 @@ bool wxSpinCtrl::SetFont(const wxFont& font)
return false;
}
WXHANDLE hFont = GetFont().GetResourceHandle();
(void)::SendMessage(GetBuddyHwnd(), WM_SETFONT, (WPARAM)hFont, TRUE);
wxSetWindowFont(GetBuddyHwnd(), GetFont());
return true;
}

View File

@@ -40,6 +40,7 @@
#include "wx/wxcrtvararg.h"
#endif
#include "wx/fontutil.h"
#include "wx/scopedptr.h"
#include "wx/stack.h"
#include "wx/sysopt.h"
@@ -2829,14 +2830,13 @@ bool wxTextCtrl::MSWSetCharFormat(const wxTextAttr& style, long start, long end)
CFM_ITALIC | CFM_BOLD | CFM_UNDERLINE | CFM_STRIKEOUT;
// fill in data from LOGFONT but recalculate lfHeight because we need
// the real height in twips and not the negative number which
// wxFillLogFont() returns (this is correct in general and works with
// the real height in twips and not the negative number used inside
// LOGFONT returns (this is correct in general and works with
// the Windows font mapper, but not here)
wxFont font(style.GetFont());
LOGFONT lf;
wxFillLogFont(&lf, &font);
LOGFONT lf = font.GetNativeFontInfo()->lf;
cf.yHeight = 20*font.GetPointSize(); // 1 pt = 20 twips
cf.bCharSet = lf.lfCharSet;
cf.bPitchAndFamily = lf.lfPitchAndFamily;
@@ -3126,8 +3126,9 @@ bool wxTextCtrl::GetStyle(long position, wxTextAttr& style)
LOGFONT lf;
// Convert the height from the units of 1/20th of the point in which
// CHARFORMAT stores it to pixel-based units used by LOGFONT.
const wxCoord ppi = wxClientDC(this).GetPPI().y;
lf.lfHeight = -MulDiv(cf.yHeight/20, ppi, 72);
// Note that RichEdit seems to always use standard DPI of 96, even when the
// window is a monitor using a higher DPI.
lf.lfHeight = wxNativeFontInfo::GetLogFontHeightAtPPI(cf.yHeight/20.0f, 96);
lf.lfWidth = 0;
lf.lfCharSet = ANSI_CHARSET; // FIXME: how to get correct charset?
lf.lfClipPrecision = 0;
@@ -3160,7 +3161,7 @@ bool wxTextCtrl::GetStyle(long position, wxTextAttr& style)
else
lf.lfWeight = FW_NORMAL;
wxFont font = wxCreateFontFromLogFont(& lf);
wxFont font(lf);
if (font.IsOk())
{
style.SetFont(font);

View File

@@ -827,11 +827,7 @@ bool wxWindowMSW::SetFont(const wxFont& font)
// just been reset and in this case we need to change the font used by
// the native window to the default for this class, i.e. exactly what
// GetFont() returns
WXHANDLE hFont = GetFont().GetResourceHandle();
wxASSERT_MSG( hFont, wxT("should have valid font") );
::SendMessage(hWnd, WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE, 0));
wxSetWindowFont(hWnd, GetFont());
}
return true;
@@ -7425,7 +7421,12 @@ static TEXTMETRIC wxGetTextMetrics(const wxWindowMSW *win)
#if !wxDIALOG_UNIT_COMPATIBILITY
// and select the current font into it
HFONT hfont = GetHfontOf(win->GetFont());
// Note that it's important to extend the lifetime of the possibly
// temporary wxFont returned by GetFont() to ensure that its HFONT remains
// valid.
const wxFont& f(win->GetFont());
HFONT hfont = GetHfontOf(f);
if ( hfont )
{
hfont = (HFONT)::SelectObject(hdc, hfont);