Update the fonts when using a different DPI.
Sean Hall committed
Jul 6, 2020 at 16:08 UTC
07175b9e5d5c89171e34e93b3fb3fb2c11601146
2 files changed
+139
-32
src/dutil/inc/thmutil.h
+15
-1
@@ -239,13 +239,27 @@ struct THEME_PAGE
239
THEME_SAVEDVARIABLE* rgSavedVariables;
240
};
241
242
-struct THEME_FONT
242
+struct THEME_FONT_INSTANCE
243
{
244
+ UINT nDpi;
245
HFONT hFont;
246
+};
247
+
248
+struct THEME_FONT
249
+{
250
+ LONG lfHeight;
251
+ LONG lfWeight;
252
+ BYTE lfUnderline;
253
+ BYTE lfQuality;
254
+ LPWSTR sczFaceName;
255
+
256
COLORREF crForeground;
257
HBRUSH hForeground;
258
COLORREF crBackground;
259
HBRUSH hBackground;
260
+
261
+ DWORD cFontInstances;
262
+ THEME_FONT_INSTANCE* rgFontInstances;
263
};
264
265
src/dutil/thmutil.cpp
+124
-31
@@ -36,6 +36,7 @@
36
37
const DWORD THEME_INVALID_ID = 0xFFFFFFFF;
38
const COLORREF THEME_INVISIBLE_COLORREF = 0xFFFFFFFF;
39
+const DWORD GROW_FONT_INSTANCES = 3;
40
const DWORD GROW_WINDOW_TEXT = 250;
41
const LPCWSTR THEME_WC_HYPERLINK = L"ThemeHyperLink";
42
const LPCWSTR THEME_WC_PANEL = L"ThemePanel";
@@ -177,6 +178,11 @@ static HRESULT StartBillboard(
178
__in THEME* pTheme,
179
__in DWORD dwControl
180
);
181
+static HRESULT EnsureFontInstance(
182
+ __in THEME* pTheme,
183
+ __in THEME_FONT* pFont,
184
+ __out THEME_FONT_INSTANCE** ppFontInstance
185
+ );
186
static HRESULT FindImageList(
187
__in THEME* pTheme,
188
__in_z LPCWSTR wzImageListName,
@@ -248,6 +254,9 @@ static DWORD CALLBACK RichEditStreamFromMemoryCallback(
254
__in LONG cb,
255
__in LONG *pcb
256
);
257
+static void FreeFontInstance(
258
+ __in THEME_FONT_INSTANCE* pFontInstance
259
+ );
260
static void FreeFont(
261
__in THEME_FONT* pFont
262
);
@@ -365,11 +374,13 @@ static void ScaleTheme(
374
__in int y
375
);
376
static void ScaleControls(
377
+ __in THEME* pTheme,
378
__in DWORD cControls,
379
__in THEME_CONTROL* rgControls,
380
__in UINT nDpi
381
);
382
static void ScaleControl(
383
+ __in THEME* pTheme,
384
__in THEME_CONTROL* pControl,
385
__in UINT nDpi
386
);
@@ -1078,7 +1089,7 @@ DAPI_(HRESULT) ThemeShowPageEx(
1089
else
1090
{
1091
hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(&pPage->rgSavedVariables), pPage->cControlIndices, sizeof(THEME_SAVEDVARIABLE), pPage->cControlIndices);
1081
- ThmExitOnNull(pPage->rgSavedVariables, hr, E_OUTOFMEMORY, "Failed to allocate memory for saved variables.");
1092
+ ThmExitOnFailure(hr, "Failed to allocate memory for saved variables.");
1093
1094
SecureZeroMemory(pPage->rgSavedVariables, MemSize(pPage->rgSavedVariables));
1095
pPage->cSavedVariables = pPage->cControlIndices;
@@ -2017,7 +2028,6 @@ static HRESULT ParseFonts(
2028
IXMLDOMNode* pixn = NULL;
2029
BSTR bstrName = NULL;
2030
DWORD dwId = 0;
2020
- LOGFONTW lf = { };
2031
COLORREF crForeground = THEME_INVISIBLE_COLORREF;
2032
COLORREF crBackground = THEME_INVISIBLE_COLORREF;
2033
DWORD dwSystemForegroundColor = FALSE;
@@ -2037,8 +2047,6 @@ static HRESULT ParseFonts(
2047
pTheme->rgFonts = static_cast<THEME_FONT*>(MemAlloc(sizeof(THEME_FONT) * pTheme->cFonts, TRUE));
2048
ThmExitOnNull(pTheme->rgFonts, hr, E_OUTOFMEMORY, "Failed to allocate theme fonts.");
2049
2040
- lf.lfQuality = CLEARTYPE_QUALITY;
2041
-
2050
while (S_OK == (hr = XmlNextElement(pixnl, &pixn, NULL)))
2051
{
2052
hr = XmlGetAttributeNumber(pixn, L"Id", &dwId);
@@ -2054,6 +2062,15 @@ static HRESULT ParseFonts(
2062
ThmExitOnRootFailure(hr, "Invalid theme font id.");
2063
}
2064
2065
+ THEME_FONT* pFont = pTheme->rgFonts + dwId;
2066
+ if (pFont->cFontInstances)
2067
+ {
2068
+ hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
2069
+ ThmExitOnRootFailure(hr, "Theme font id duplicated.");
2070
+ }
2071
+
2072
+ pFont->lfQuality = CLEARTYPE_QUALITY;
2073
+
2074
hr = XmlGetText(pixn, &bstrName);
2075
if (S_FALSE == hr)
2076
{
@@ -2061,28 +2078,28 @@ static HRESULT ParseFonts(
2078
}
2079
ThmExitOnFailure(hr, "Failed to get font name.");
2080
2064
- hr = ::StringCchCopyW(lf.lfFaceName, countof(lf.lfFaceName), bstrName);
2081
+ hr = StrAllocString(&pFont->sczFaceName, bstrName, 0);
2082
ThmExitOnFailure(hr, "Failed to copy font name.");
2083
2067
- hr = XmlGetAttributeNumber(pixn, L"Height", reinterpret_cast<DWORD*>(&lf.lfHeight));
2084
+ hr = XmlGetAttributeNumber(pixn, L"Height", reinterpret_cast<DWORD*>(&pFont->lfHeight));
2085
if (S_FALSE == hr)
2086
{
2087
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
2088
}
2089
ThmExitOnFailure(hr, "Failed to find font height attribute.");
2090
2074
- hr = XmlGetAttributeNumber(pixn, L"Weight", reinterpret_cast<DWORD*>(&lf.lfWeight));
2091
+ hr = XmlGetAttributeNumber(pixn, L"Weight", reinterpret_cast<DWORD*>(&pFont->lfWeight));
2092
if (S_FALSE == hr)
2093
{
2077
- lf.lfWeight = FW_DONTCARE;
2094
+ pFont->lfWeight = FW_DONTCARE;
2095
hr = S_OK;
2096
}
2097
ThmExitOnFailure(hr, "Failed to find font weight attribute.");
2098
2082
- hr = XmlGetYesNoAttribute(pixn, L"Underline", reinterpret_cast<BOOL*>(&lf.lfUnderline));
2099
+ hr = XmlGetYesNoAttribute(pixn, L"Underline", reinterpret_cast<BOOL*>(&pFont->lfUnderline));
2100
if (E_NOTFOUND == hr)
2101
{
2085
- lf.lfUnderline = FALSE;
2102
+ pFont->lfUnderline = FALSE;
2103
hr = S_OK;
2104
}
2105
ThmExitOnFailure(hr, "Failed to find font underline attribute.");
@@ -2093,28 +2110,18 @@ static HRESULT ParseFonts(
2110
hr = GetFontColor(pixn, L"Background", &crBackground, &dwSystemBackgroundColor);
2111
ThmExitOnFailure(hr, "Failed to find font background color.");
2112
2096
- THEME_FONT* pFont = pTheme->rgFonts + dwId;
2097
- if (pFont->hFont)
2098
- {
2099
- hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
2100
- ThmExitOnRootFailure(hr, "Theme font id duplicated.");
2101
- }
2102
-
2103
- pFont->hFont = ::CreateFontIndirectW(&lf);
2104
- ThmExitOnNullWithLastError(pFont->hFont, hr, "Failed to create font %u.", dwId);
2105
-
2113
pFont->crForeground = crForeground;
2114
if (THEME_INVISIBLE_COLORREF != pFont->crForeground)
2115
{
2116
pFont->hForeground = dwSystemForegroundColor ? ::GetSysColorBrush(dwSystemForegroundColor) : ::CreateSolidBrush(pFont->crForeground);
2110
- ThmExitOnNullWithLastError(pFont->hForeground, hr, "Failed to create text foreground brush.");
2117
+ ThmExitOnNull(pFont->hForeground, hr, E_OUTOFMEMORY, "Failed to create text foreground brush.");
2118
}
2119
2120
pFont->crBackground = crBackground;
2121
if (THEME_INVISIBLE_COLORREF != pFont->crBackground)
2122
{
2123
pFont->hBackground = dwSystemBackgroundColor ? ::GetSysColorBrush(dwSystemBackgroundColor) : ::CreateSolidBrush(pFont->crBackground);
2117
- ThmExitOnNullWithLastError(pFont->hBackground, hr, "Failed to create text background brush.");
2124
+ ThmExitOnNull(pFont->hBackground, hr, E_OUTOFMEMORY, "Failed to create text background brush.");
2125
}
2126
2127
ReleaseNullBSTR(bstrName);
@@ -3577,6 +3584,50 @@ static HRESULT StopBillboard(
3584
return hr;
3585
}
3586
3587
+static HRESULT EnsureFontInstance(
3588
+ __in THEME* pTheme,
3589
+ __in THEME_FONT* pFont,
3590
+ __out THEME_FONT_INSTANCE** ppFontInstance
3591
+ )
3592
+{
3593
+ HRESULT hr = S_OK;
3594
+ THEME_FONT_INSTANCE* pFontInstance = NULL;
3595
+ LOGFONTW lf = { };
3596
+
3597
+ for (DWORD i = 0; i < pFont->cFontInstances; ++i)
3598
+ {
3599
+ pFontInstance = pFont->rgFontInstances + i;
3600
+ if (pTheme->nDpi == pFontInstance->nDpi)
3601
+ {
3602
+ *ppFontInstance = pFontInstance;
3603
+ ExitFunction();
3604
+ }
3605
+ }
3606
+
3607
+ hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(&pFont->rgFontInstances), pFont->cFontInstances, sizeof(THEME_FONT_INSTANCE), GROW_FONT_INSTANCES);
3608
+ ThmExitOnFailure(hr, "Failed to allocate memory for font instances.");
3609
+
3610
+ pFontInstance = pFont->rgFontInstances + pFont->cFontInstances;
3611
+ pFontInstance->nDpi = pTheme->nDpi;
3612
+
3613
+ lf.lfHeight = DpiuScaleValue(pFont->lfHeight, pFontInstance->nDpi);
3614
+ lf.lfWeight = pFont->lfWeight;
3615
+ lf.lfUnderline = pFont->lfUnderline;
3616
+ lf.lfQuality = pFont->lfQuality;
3617
+
3618
+ hr = ::StringCchCopyW(lf.lfFaceName, countof(lf.lfFaceName), pFont->sczFaceName);
3619
+ ThmExitOnFailure(hr, "Failed to copy font name to create font.");
3620
+
3621
+ pFontInstance->hFont = ::CreateFontIndirectW(&lf);
3622
+ ThmExitOnNull(pFontInstance->hFont, hr, E_OUTOFMEMORY, "Failed to create DPI specific font.");
3623
+
3624
+ ++pFont->cFontInstances;
3625
+ *ppFontInstance = pFontInstance;
3626
+
3627
+LExit:
3628
+ return hr;
3629
+}
3630
+
3631
3632
static HRESULT FindImageList(
3633
__in THEME* pTheme,
@@ -3661,9 +3712,11 @@ static void DrawControlText(
3712
__in BOOL fDrawFocusRect
3713
)
3714
{
3715
+ HRESULT hr = S_OK;
3716
WCHAR wzText[256] = { };
3717
DWORD cchText = 0;
3718
THEME_FONT* pFont = NULL;
3719
+ THEME_FONT_INSTANCE* pFontInstance = NULL;
3720
HFONT hfPrev = NULL;
3721
3722
if (0 == (cchText = ::GetWindowTextW(pdis->hwndItem, wzText, countof(wzText))))
@@ -3685,7 +3738,11 @@ static void DrawControlText(
3738
pFont = pTheme->rgFonts + pControl->dwFontId;
3739
}
3740
3688
- hfPrev = SelectFont(pdis->hDC, pFont->hFont);
3741
+ hr = EnsureFontInstance(pTheme, pFont, &pFontInstance);
3742
+ if (SUCCEEDED(hr))
3743
+ {
3744
+ hfPrev = SelectFont(pdis->hDC, pFontInstance->hFont);
3745
+ }
3746
3747
::DrawTextExW(pdis->hDC, wzText, cchText, &pdis->rcItem, DT_SINGLELINE | (fCentered ? (DT_CENTER | DT_VCENTER) : 0), NULL);
3748
@@ -3694,7 +3751,10 @@ static void DrawControlText(
3751
::DrawFocusRect(pdis->hDC, &pdis->rcItem);
3752
}
3753
3697
- SelectFont(pdis->hDC, hfPrev);
3754
+ if (hfPrev)
3755
+ {
3756
+ SelectFont(pdis->hDC, hfPrev);
3757
+ }
3758
}
3759
3760
@@ -3939,6 +3999,18 @@ static void FreeTab(
3999
}
4000
4001
4002
+static void FreeFontInstance(
4003
+ __in THEME_FONT_INSTANCE* pFontInstance
4004
+ )
4005
+{
4006
+ if (pFontInstance->hFont)
4007
+ {
4008
+ ::DeleteObject(pFontInstance->hFont);
4009
+ pFontInstance->hFont = NULL;
4010
+ }
4011
+}
4012
+
4013
+
4014
static void FreeFont(
4015
__in THEME_FONT* pFont
4016
)
@@ -3957,11 +4029,13 @@ static void FreeFont(
4029
pFont->hForeground = NULL;
4030
}
4031
3960
- if (pFont->hFont)
4032
+ for (DWORD i = 0; i < pFont->cFontInstances; ++i)
4033
{
3962
- ::DeleteObject(pFont->hFont);
3963
- pFont->hFont = NULL;
4034
+ FreeFontInstance(&(pFont->rgFontInstances[i]));
4035
}
4036
+
4037
+ ReleaseMem(pFont->rgFontInstances);
4038
+ ReleaseStr(pFont->sczFaceName);
4039
}
4040
}
4041
@@ -4784,6 +4858,7 @@ static HRESULT LoadControls(
4858
{
4859
THEME_CONTROL* pControl = rgControls + i;
4860
THEME_FONT* pControlFont = (pTheme->cFonts > pControl->dwFontId) ? pTheme->rgFonts + pControl->dwFontId : NULL;
4861
+ THEME_FONT_INSTANCE* pControlFontInstance = NULL;
4862
LPCWSTR wzWindowClass = NULL;
4863
DWORD dwWindowBits = WS_CHILD;
4864
DWORD dwWindowExBits = 0;
@@ -5097,7 +5172,10 @@ static HRESULT LoadControls(
5172
5173
if (pControlFont)
5174
{
5100
- ::SendMessageW(pControl->hWnd, WM_SETFONT, (WPARAM) pControlFont->hFont, FALSE);
5175
+ hr = EnsureFontInstance(pTheme, pControlFont, &pControlFontInstance);
5176
+ ThmExitOnFailure(hr, "Failed to get DPI specific font.");
5177
+
5178
+ ::SendMessageW(pControl->hWnd, WM_SETFONT, (WPARAM) pControlFontInstance->hFont, FALSE);
5179
}
5180
5181
// Initialize the text on all "application" (non-page) controls, best effort only.
@@ -5379,12 +5457,13 @@ static void ScaleTheme(
5457
pTheme->nMinimumHeight = DpiuScaleValue(pTheme->nDefaultDpiMinimumHeight, pTheme->nDpi);
5458
pTheme->nMinimumWidth = DpiuScaleValue(pTheme->nDefaultDpiMinimumWidth, pTheme->nDpi);
5459
5382
- ScaleControls(pTheme->cControls, pTheme->rgControls, pTheme->nDpi);
5460
+ ScaleControls(pTheme, pTheme->cControls, pTheme->rgControls, pTheme->nDpi);
5461
5462
::SetWindowPos(pTheme->hwndParent, NULL, x, y, pTheme->nWidth, pTheme->nHeight, SWP_NOACTIVATE | SWP_NOZORDER);
5463
}
5464
5465
static void ScaleControls(
5466
+ __in THEME* pTheme,
5467
__in DWORD cControls,
5468
__in THEME_CONTROL* rgControls,
5469
__in UINT nDpi
@@ -5393,15 +5472,29 @@ static void ScaleControls(
5472
for (DWORD i = 0; i < cControls; ++i)
5473
{
5474
THEME_CONTROL* pControl = rgControls + i;
5396
- ScaleControl(pControl, nDpi);
5475
+ ScaleControl(pTheme, pControl, nDpi);
5476
}
5477
}
5478
5479
static void ScaleControl(
5480
+ __in THEME* pTheme,
5481
__in THEME_CONTROL* pControl,
5482
__in UINT nDpi
5483
)
5484
{
5485
+ HRESULT hr = S_OK;
5486
+ THEME_FONT* pControlFont = (pTheme->cFonts > pControl->dwFontId) ? pTheme->rgFonts + pControl->dwFontId : NULL;
5487
+ THEME_FONT_INSTANCE* pControlFontInstance = NULL;
5488
+
5489
+ if (pControlFont)
5490
+ {
5491
+ hr = EnsureFontInstance(pTheme, pControlFont, &pControlFontInstance);
5492
+ if (SUCCEEDED(hr) && pControl->hWnd)
5493
+ {
5494
+ ::SendMessageW(pControl->hWnd, WM_SETFONT, (WPARAM)pControlFontInstance->hFont, FALSE);
5495
+ }
5496
+ }
5497
+
5498
pControl->nWidth = DpiuScaleValue(pControl->nDefaultDpiWidth, nDpi);
5499
pControl->nHeight = DpiuScaleValue(pControl->nDefaultDpiHeight, nDpi);
5500
pControl->nX = DpiuScaleValue(pControl->nDefaultDpiX, nDpi);
@@ -5409,7 +5502,7 @@ static void ScaleControl(
5502
5503
if (pControl->cControls)
5504
{
5412
- ScaleControls(pControl->cControls, pControl->rgControls, nDpi);
5505
+ ScaleControls(pTheme, pControl->cControls, pControl->rgControls, nDpi);
5506
}
5507
}
5508