@joebigelow / wix-1 / commits / 07175b9e

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