@joebigelow / wix-1 / commits / b22a62fd

Add THEME_IMAGE_REFERENCE to thmutil.

Sean Hall committed Jun 4, 2021 at 13:15 UTC b22a62fd6eed5bb7a2c04d51828438daa621db6c
2 files changed +293 -70
src/libs/dutil/WixToolset.DUtil/inc/thmutil.h
+29 -6
@@ -75,6 +75,13 @@ typedef enum THEME_CONTROL_TYPE
75 THEME_CONTROL_TYPE_TAB,
76 } THEME_CONTROL_TYPE;
77
78 +typedef enum THEME_IMAGE_REFERENCE_TYPE
79 +{
80 + THEME_IMAGE_REFERENCE_TYPE_NONE,
81 + THEME_IMAGE_REFERENCE_TYPE_PARTIAL,
82 + THEME_IMAGE_REFERENCE_TYPE_COMPLETE,
83 +} THEME_IMAGE_REFERENCE_TYPE;
84 +
85 typedef enum THEME_SHOW_PAGE_REASON
86 {
87 THEME_SHOW_PAGE_REASON_DEFAULT,
@@ -100,6 +107,22 @@ struct THEME_COLUMN
107 };
108
109
110 +struct THEME_IMAGE_REFERENCE
111 +{
112 + THEME_IMAGE_REFERENCE_TYPE type;
113 + DWORD dwImageInstanceIndex;
114 + int nX;
115 + int nY;
116 + int nHeight;
117 + int nWidth;
118 +};
119 +
120 +struct THEME_IMAGE_INSTANCE
121 +{
122 + Gdiplus::Bitmap* pBitmap;
123 +};
124 +
125 +
126 struct THEME_TAB
127 {
128 LPWSTR pszName;
@@ -159,15 +182,13 @@ struct THEME_CONTROL
182 int nY;
183 int nHeight;
184 int nWidth;
162 - int nSourceX;
163 - int nSourceY;
185 UINT uStringId;
186
187 LPWSTR sczEnableCondition;
188 LPWSTR sczVisibleCondition;
189 BOOL fDisableVariableFunctionality;
190
170 - Gdiplus::Bitmap* pBitmap;
191 + THEME_IMAGE_REFERENCE imageRef;
192 HBITMAP hImage;
193 HICON hIcon;
194
@@ -293,15 +314,17 @@ struct THEME
314 int nMinimumWidth;
315 int nWindowHeight;
316 int nWindowWidth;
296 - int nSourceX;
297 - int nSourceY;
317 UINT uStringId;
318
300 - Gdiplus::Bitmap* pBitmap;
319 + DWORD dwSourceImageInstanceIndex;
320 + THEME_IMAGE_REFERENCE windowImageRef;
321
322 DWORD cFonts;
323 THEME_FONT* rgFonts;
324
325 + DWORD cStandaloneImages;
326 + THEME_IMAGE_INSTANCE* rgStandaloneImages;
327 +
328 DWORD cPages;
329 THEME_PAGE* rgPages;
330
src/libs/dutil/WixToolset.DUtil/thmutil.cpp
+264 -64
@@ -42,6 +42,7 @@
42 const DWORD THEME_INVALID_ID = 0xFFFFFFFF;
43 const COLORREF THEME_INVISIBLE_COLORREF = 0xFFFFFFFF;
44 const DWORD GROW_FONT_INSTANCES = 3;
45 +const DWORD GROW_IMAGE_INSTANCES = 5;
46 const DWORD GROW_WINDOW_TEXT = 250;
47 const LPCWSTR THEME_WC_HYPERLINK = L"ThemeHyperLink";
48 const LPCWSTR THEME_WC_PANEL = L"ThemePanel";
@@ -87,6 +88,11 @@ static HRESULT ParseTheme(
88 __in IXMLDOMDocument* pixd,
89 __out THEME** ppTheme
90 );
91 +static HRESULT AddStandaloneImage(
92 + __in THEME* pTheme,
93 + __in Gdiplus::Bitmap** ppBitmap,
94 + __out DWORD* pdwIndex
95 + );
96 static HRESULT GetAttributeImageFileOrResource(
97 __in_opt HMODULE hModule,
98 __in_z_opt LPCWSTR wzRelativePath,
@@ -118,9 +124,10 @@ static HRESULT GetAttributeFontId(
124 );
125 static HRESULT ParseSourceXY(
126 __in IXMLDOMNode* pixn,
121 - __in BOOL fAllowed,
122 - __inout int* pnX,
123 - __inout int* pnY
127 + __in THEME* pTheme,
128 + __in int nWidth,
129 + __in int nHeight,
130 + __inout THEME_IMAGE_REFERENCE* pReference
131 );
132 static HRESULT ParseWindow(
133 __in_opt HMODULE hModule,
@@ -281,6 +288,20 @@ static HRESULT DrawImage(
288 __in DRAWITEMSTRUCT* pdis,
289 __in const THEME_CONTROL* pControl
290 );
291 +static void GetImageInstance(
292 + __in THEME* pTheme,
293 + __in const THEME_IMAGE_REFERENCE* pReference,
294 + __out const THEME_IMAGE_INSTANCE** ppInstance
295 + );
296 +static HRESULT DrawImageReference(
297 + __in THEME* pTheme,
298 + __in const THEME_IMAGE_REFERENCE* pReference,
299 + __in HDC hdc,
300 + __in int destX,
301 + __in int destY,
302 + __in int destWidth,
303 + __in int destHeight
304 + );
305 static HRESULT DrawGdipBitmap(
306 __in HDC hdc,
307 __in int destX,
@@ -300,7 +321,7 @@ static HRESULT DrawProgressBar(
321 );
322 static HRESULT DrawProgressBarImage(
323 __in THEME* pTheme,
303 - __in Gdiplus::Bitmap* pBitmap,
324 + __in const THEME_IMAGE_INSTANCE* pImageInstance,
325 __in int srcX,
326 __in int srcY,
327 __in int srcWidth,
@@ -333,6 +354,9 @@ static void FreeFontInstance(
354 static void FreeFont(
355 __in THEME_FONT* pFont
356 );
357 +static void FreeImageInstance(
358 + __in THEME_IMAGE_INSTANCE* pImageInstance
359 + );
360 static void FreePage(
361 __in THEME_PAGE* pPage
362 );
@@ -644,6 +668,11 @@ DAPI_(void) ThemeFree(
668 FreeFont(pTheme->rgFonts + i);
669 }
670
671 + for (DWORD i = 0; i < pTheme->cStandaloneImages; ++i)
672 + {
673 + FreeImageInstance(pTheme->rgStandaloneImages + i);
674 + }
675 +
676 for (DWORD i = 0; i < pTheme->cPages; ++i)
677 {
678 FreePage(pTheme->rgPages + i);
@@ -661,13 +690,9 @@ DAPI_(void) ThemeFree(
690
691 ReleaseMem(pTheme->rgControls);
692 ReleaseMem(pTheme->rgPages);
693 + ReleaseMem(pTheme->rgStandaloneImages);
694 ReleaseMem(pTheme->rgFonts);
695
666 - if (pTheme->pBitmap)
667 - {
668 - delete pTheme->pBitmap;
669 - }
670 -
696 ReleaseStr(pTheme->sczCaption);
697 ReleaseMem(pTheme);
698 }
@@ -1305,9 +1330,9 @@ DAPI_(HRESULT) ThemeDrawBackground(
1330 {
1331 HRESULT hr = S_FALSE;
1332
1308 - if (pTheme->pBitmap && 0 <= pTheme->nSourceX && 0 <= pTheme->nSourceY && pps->fErase)
1333 + if (pps->fErase && THEME_IMAGE_REFERENCE_TYPE_NONE != pTheme->windowImageRef.type)
1334 {
1310 - hr = DrawGdipBitmap(pps->hdc, 0, 0, pTheme->nWidth, pTheme->nHeight, pTheme->pBitmap, pTheme->nSourceX, pTheme->nSourceY, pTheme->nDefaultDpiWidth, pTheme->nDefaultDpiHeight);
1335 + hr = DrawImageReference(pTheme, &pTheme->windowImageRef, pps->hdc, 0, 0, pTheme->nWidth, pTheme->nHeight);
1336 }
1337
1338 return hr;
@@ -1743,6 +1768,7 @@ static HRESULT ParseTheme(
1768 HRESULT hr = S_OK;
1769 THEME* pTheme = NULL;
1770 IXMLDOMElement *pThemeElement = NULL;
1771 + Gdiplus::Bitmap* pBitmap = NULL;
1772 BOOL fXmlFound = FALSE;
1773
1774 hr = pixd->get_documentElement(&pThemeElement);
@@ -1755,9 +1781,19 @@ static HRESULT ParseTheme(
1781 pTheme->nDpi = USER_DEFAULT_SCREEN_DPI;
1782
1783 // Parse the optional background resource image.
1758 - hr = GetAttributeImageFileOrResource(hModule, wzRelativePath, pThemeElement, &pTheme->pBitmap);
1784 + hr = GetAttributeImageFileOrResource(hModule, wzRelativePath, pThemeElement, &pBitmap);
1785 ThmExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed while parsing theme image.");
1786
1787 + if (fXmlFound)
1788 + {
1789 + hr = AddStandaloneImage(pTheme, &pBitmap, &pTheme->dwSourceImageInstanceIndex);
1790 + ThmExitOnFailure(hr, "Failed to store theme image.");
1791 + }
1792 + else
1793 + {
1794 + pTheme->dwSourceImageInstanceIndex = THEME_INVALID_ID;
1795 + }
1796 +
1797 // Parse the fonts.
1798 hr = ParseFonts(pThemeElement, pTheme);
1799 ThmExitOnFailure(hr, "Failed to parse theme fonts.");
@@ -1772,6 +1808,11 @@ static HRESULT ParseTheme(
1808 LExit:
1809 ReleaseObject(pThemeElement);
1810
1811 + if (pBitmap)
1812 + {
1813 + delete pBitmap;
1814 + }
1815 +
1816 if (pTheme)
1817 {
1818 ThemeFree(pTheme);
@@ -1780,6 +1821,30 @@ LExit:
1821 return hr;
1822 }
1823
1824 +static HRESULT AddStandaloneImage(
1825 + __in THEME* pTheme,
1826 + __in Gdiplus::Bitmap** ppBitmap,
1827 + __out DWORD* pdwIndex
1828 + )
1829 +{
1830 + HRESULT hr = S_OK;
1831 + THEME_IMAGE_INSTANCE* pInstance = NULL;
1832 +
1833 + hr = MemEnsureArraySizeForNewItems(reinterpret_cast<LPVOID*>(&pTheme->rgStandaloneImages), pTheme->cStandaloneImages, 1, sizeof(THEME_IMAGE_INSTANCE), GROW_IMAGE_INSTANCES);
1834 + ThmExitOnFailure(hr, "Failed to allocate memory for image instances.");
1835 +
1836 + *pdwIndex = pTheme->cStandaloneImages;
1837 + ++pTheme->cStandaloneImages;
1838 +
1839 + pInstance = pTheme->rgStandaloneImages + *pdwIndex;
1840 +
1841 + pInstance->pBitmap = *ppBitmap;
1842 + *ppBitmap = NULL;
1843 +
1844 +LExit:
1845 + return hr;
1846 +}
1847 +
1848 static HRESULT GetAttributeImageFileOrResource(
1849 __in_opt HMODULE hModule,
1850 __in_z_opt LPCWSTR wzRelativePath,
@@ -1864,17 +1929,23 @@ static HRESULT ParseOwnerDrawImage(
1929 HRESULT hr = S_OK;
1930 BOOL fXmlFound = FALSE;
1931 BOOL fFoundImage = FALSE;
1932 + Gdiplus::Bitmap* pBitmap = NULL;
1933
1934 // Parse the optional background resource image.
1869 - hr = GetAttributeImageFileOrResource(hModule, wzRelativePath, pElement, &pControl->pBitmap);
1935 + hr = GetAttributeImageFileOrResource(hModule, wzRelativePath, pElement, &pBitmap);
1936 ThmExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed while parsing control image.");
1937
1938 if (fXmlFound)
1939 {
1940 + hr = AddStandaloneImage(pTheme, &pBitmap, &pControl->imageRef.dwImageInstanceIndex);
1941 + ThmExitOnFailure(hr, "Failed to store owner draw image.");
1942 +
1943 + pControl->imageRef.type = THEME_IMAGE_REFERENCE_TYPE_COMPLETE;
1944 +
1945 fFoundImage = TRUE;
1946 }
1947
1877 - hr = ParseSourceXY(pElement, NULL != pTheme->pBitmap, &pControl->nSourceX, &pControl->nSourceY);
1948 + hr = ParseSourceXY(pElement, pTheme, pControl->nWidth, pControl->nHeight, &pControl->imageRef);
1949 ThmExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to get control SourceX and SourceY attributes.");
1950
1951 if (fXmlFound)
@@ -1897,6 +1968,11 @@ static HRESULT ParseOwnerDrawImage(
1968 }
1969
1970 LExit:
1971 + if (pBitmap)
1972 + {
1973 + delete pBitmap;
1974 + }
1975 +
1976 return hr;
1977 }
1978
@@ -2042,35 +2118,50 @@ LExit:
2118
2119 static HRESULT ParseSourceXY(
2120 __in IXMLDOMNode* pixn,
2045 - __in BOOL fAllowed,
2046 - __inout int* pnX,
2047 - __inout int* pnY
2121 + __in THEME* pTheme,
2122 + __in int nWidth,
2123 + __in int nHeight,
2124 + __inout THEME_IMAGE_REFERENCE* pReference
2125 )
2126 {
2127 HRESULT hr = S_OK;
2128 BOOL fXFound = FALSE;
2129 BOOL fYFound = FALSE;
2053 -
2054 - hr = GetAttributeCoordinateOrDimension(pixn, L"SourceX", pnX);
2130 + int nX = 0;
2131 + int nY = 0;
2132 + DWORD dwImageInstanceIndex = pTheme->dwSourceImageInstanceIndex;
2133 + THEME_IMAGE_INSTANCE* pInstance = THEME_INVALID_ID != dwImageInstanceIndex ? pTheme->rgStandaloneImages + dwImageInstanceIndex : NULL;
2134 + int nSourceWidth = pInstance ? pInstance->pBitmap->GetWidth() : 0;
2135 + int nSourceHeight = pInstance ? pInstance->pBitmap->GetHeight() : 0;
2136 +
2137 + hr = GetAttributeCoordinateOrDimension(pixn, L"SourceX", &nX);
2138 ThmExitOnOptionalXmlQueryFailure(hr, fXFound, "Failed to get SourceX attribute.");
2139
2140 if (!fXFound)
2141 {
2059 - *pnX = -1;
2142 + nX = -1;
2143 }
2144 else
2145 {
2063 - if (!fAllowed)
2146 + if (!pInstance)
2147 {
2148 ThmExitWithRootFailure(hr, E_INVALIDDATA, "SourceX cannot be specified without an image specified on Theme.");
2149 }
2067 - else if (0 > *pnX)
2150 + else if (0 > nX)
2151 {
2152 ThmExitWithRootFailure(hr, E_INVALIDDATA, "SourceX must be non-negative.");
2153 }
2154 + else if (nSourceWidth <= nX)
2155 + {
2156 + ThmExitWithRootFailure(hr, E_INVALIDDATA, "SourceX (%i) must be less than the image width: %i.", nX, nSourceWidth);
2157 + }
2158 + else if (nSourceWidth <= (nX + nWidth))
2159 + {
2160 + ThmExitWithRootFailure(hr, E_INVALIDDATA, "SourceX (%i) with width %i must be less than the image width: %i.", nX, nWidth, nSourceWidth);
2161 + }
2162 }
2163
2073 - hr = GetAttributeCoordinateOrDimension(pixn, L"SourceY", pnY);
2164 + hr = GetAttributeCoordinateOrDimension(pixn, L"SourceY", &nY);
2165 ThmExitOnOptionalXmlQueryFailure(hr, fYFound, "Failed to get SourceY attribute.");
2166
2167 if (!fYFound)
@@ -2080,12 +2171,11 @@ static HRESULT ParseSourceXY(
2171 ThmExitWithRootFailure(hr, E_INVALIDDATA, "SourceY must be specified with SourceX.");
2172 }
2173
2083 - *pnY = -1;
2084 - hr = E_NOTFOUND;
2174 + ExitFunction1(hr = E_NOTFOUND);
2175 }
2176 else
2177 {
2088 - if (!fAllowed)
2178 + if (!pInstance)
2179 {
2180 ThmExitWithRootFailure(hr, E_INVALIDDATA, "SourceY cannot be specified without an image specified on Theme.");
2181 }
@@ -2093,12 +2183,27 @@ static HRESULT ParseSourceXY(
2183 {
2184 ThmExitWithRootFailure(hr, E_INVALIDDATA, "SourceY must be specified with SourceX.");
2185 }
2096 - else if (0 > *pnY)
2186 + else if (0 > nY)
2187 {
2188 ThmExitWithRootFailure(hr, E_INVALIDDATA, "SourceY must be non-negative.");
2189 }
2190 + else if (nSourceHeight <= nY)
2191 + {
2192 + ThmExitWithRootFailure(hr, E_INVALIDDATA, "SourceY (%i) must be less than the image height: %i.", nY, nSourceHeight);
2193 + }
2194 + else if (nSourceHeight <= (nY + nHeight))
2195 + {
2196 + ThmExitWithRootFailure(hr, E_INVALIDDATA, "SourceY (%i) with height %i must be less than the image height: %i.", nY, nHeight, nSourceHeight);
2197 + }
2198 }
2199
2200 + pReference->type = THEME_IMAGE_REFERENCE_TYPE_PARTIAL;
2201 + pReference->dwImageInstanceIndex = dwImageInstanceIndex;
2202 + pReference->nX = nX;
2203 + pReference->nY = nY;
2204 + pReference->nWidth = nWidth;
2205 + pReference->nHeight = nHeight;
2206 +
2207 LExit:
2208 return hr;
2209 }
@@ -2220,7 +2325,7 @@ static HRESULT ParseWindow(
2325 ReleaseNullBSTR(bstr);
2326 }
2327
2223 - hr = ParseSourceXY(pixn, NULL != pTheme->pBitmap, &pTheme->nSourceX, &pTheme->nSourceY);
2328 + hr = ParseSourceXY(pixn, pTheme, pTheme->nDefaultDpiWidth, pTheme->nDefaultDpiHeight, &pTheme->windowImageRef);
2329 ThmExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to get window SourceX and SourceY attributes.");
2330
2331 // Parse the optional window style.
@@ -2230,7 +2335,7 @@ static HRESULT ParseWindow(
2335 if (!fXmlFound)
2336 {
2337 pTheme->dwStyle = WS_VISIBLE | WS_MINIMIZEBOX | WS_SYSMENU | WS_CAPTION;
2233 - pTheme->dwStyle |= (0 <= pTheme->nSourceX && 0 <= pTheme->nSourceY) ? WS_POPUP : WS_OVERLAPPED;
2338 + pTheme->dwStyle |= (THEME_IMAGE_REFERENCE_TYPE_NONE != pTheme->windowImageRef.type) ? WS_POPUP : WS_OVERLAPPED;
2339 }
2340
2341 hr = XmlGetAttributeUInt32(pixn, L"StringId", reinterpret_cast<DWORD*>(&pTheme->uStringId));
@@ -3171,8 +3276,6 @@ static void InitializeThemeControl(
3276 pControl->dwFontHoverId = THEME_INVALID_ID;
3277 pControl->dwFontId = THEME_INVALID_ID;
3278 pControl->dwFontSelectedId = THEME_INVALID_ID;
3174 - pControl->nSourceX = -1;
3175 - pControl->nSourceY = -1;
3279 pControl->uStringId = UINT_MAX;
3280 }
3281
@@ -3889,35 +3992,57 @@ static HRESULT DrawButton(
3992 )
3993 {
3994 HRESULT hr = S_OK;
3892 - int nSourceX = pControl->pBitmap ? 0 : pControl->nSourceX;
3893 - int nSourceY = pControl->pBitmap ? 0 : pControl->nSourceY;
3894 - int nSourceWidth = pControl->pBitmap ? pControl->pBitmap->GetWidth() : pControl->nDefaultDpiWidth;
3895 - int nSourceHeight = pControl->pBitmap ? pControl->pBitmap->GetHeight() / 4 : pControl->nDefaultDpiHeight;
3896 - Gdiplus::Bitmap* pBitmap = pControl->pBitmap ? pControl->pBitmap : pTheme->pBitmap;
3995 + THEME_IMAGE_REFERENCE buttonImageRef = { };
3996 + const THEME_IMAGE_INSTANCE* pInstance = NULL;
3997 int nHeight = pdis->rcItem.bottom - pdis->rcItem.top;
3998 int nWidth = pdis->rcItem.right - pdis->rcItem.left;
3999
4000 + buttonImageRef.type = THEME_IMAGE_REFERENCE_TYPE_PARTIAL;
4001 + buttonImageRef.dwImageInstanceIndex = pControl->imageRef.dwImageInstanceIndex;
4002 + GetImageInstance(pTheme, &pControl->imageRef, &pInstance);
4003 +
4004 + if (THEME_IMAGE_REFERENCE_TYPE_PARTIAL == pControl->imageRef.type)
4005 + {
4006 + buttonImageRef.nX = pControl->imageRef.nX;
4007 + buttonImageRef.nY = pControl->imageRef.nY;
4008 + buttonImageRef.nWidth = pControl->imageRef.nWidth;
4009 + buttonImageRef.nHeight = pControl->imageRef.nHeight;
4010 + }
4011 + else if (THEME_IMAGE_REFERENCE_TYPE_COMPLETE == pControl->imageRef.type)
4012 + {
4013 + buttonImageRef.nX = 0;
4014 + buttonImageRef.nY = 0;
4015 + buttonImageRef.nWidth = pInstance->pBitmap->GetWidth();
4016 + buttonImageRef.nHeight = pInstance->pBitmap->GetHeight() / 4;
4017 + }
4018 + else
4019 + {
4020 + AssertSz(FALSE, "Invalid image reference type for drawing");
4021 + ExitFunction1(hr = E_INVALIDARG);
4022 + }
4023 +
4024 DWORD_PTR dwStyle = ::GetWindowLongPtrW(pdis->hwndItem, GWL_STYLE);
4025 // "clicked" gets priority
4026 if (ODS_SELECTED & pdis->itemState)
4027 {
3904 - nSourceY += nSourceHeight * 2;
4028 + buttonImageRef.nY += buttonImageRef.nHeight * 2;
4029 }
4030 // then hover
4031 else if (pControl->dwData & THEME_CONTROL_DATA_HOVER)
4032 {
3909 - nSourceY += nSourceHeight;
4033 + buttonImageRef.nY += buttonImageRef.nHeight;
4034 }
4035 // then focused
4036 else if ((WS_TABSTOP & dwStyle) && (ODS_FOCUS & pdis->itemState))
4037 {
3914 - nSourceY += nSourceHeight * 3;
4038 + buttonImageRef.nY += buttonImageRef.nHeight * 3;
4039 }
4040
3917 - hr = DrawGdipBitmap(pdis->hDC, 0, 0, nWidth, nHeight, pBitmap, nSourceX, nSourceY, nSourceWidth, nSourceHeight);
4041 + hr = DrawImageReference(pTheme, &buttonImageRef, pdis->hDC, 0, 0, nWidth, nHeight);
4042
4043 DrawControlText(pTheme, pdis, pControl, TRUE, FALSE);
4044
4045 +LExit:
4046 return hr;
4047 }
4048
@@ -3996,17 +4121,65 @@ static HRESULT DrawImage(
4121 HRESULT hr = S_OK;
4122 int nHeight = pdis->rcItem.bottom - pdis->rcItem.top;
4123 int nWidth = pdis->rcItem.right - pdis->rcItem.left;
3999 - int nSourceX = pControl->pBitmap ? 0 : pControl->nSourceX;
4000 - int nSourceY = pControl->pBitmap ? 0 : pControl->nSourceY;
4001 - int nSourceWidth = pControl->pBitmap ? pControl->pBitmap->GetWidth() : pControl->nDefaultDpiWidth;
4002 - int nSourceHeight = pControl->pBitmap ? pControl->pBitmap->GetHeight() : pControl->nDefaultDpiHeight;
4003 - Gdiplus::Bitmap* pBitmap = pControl->pBitmap ? pControl->pBitmap : pTheme->pBitmap;
4124
4005 - hr = DrawGdipBitmap(pdis->hDC, 0, 0, nWidth, nHeight, pBitmap, nSourceX, nSourceY, nSourceWidth, nSourceHeight);
4125 + hr = DrawImageReference(pTheme, &pControl->imageRef, pdis->hDC, 0, 0, nWidth, nHeight);
4126
4127 return hr;
4128 }
4129
4130 +static void GetImageInstance(
4131 + __in THEME* pTheme,
4132 + __in const THEME_IMAGE_REFERENCE* pReference,
4133 + __out const THEME_IMAGE_INSTANCE** ppInstance
4134 + )
4135 +{
4136 + *ppInstance = pTheme->rgStandaloneImages + pReference->dwImageInstanceIndex;
4137 +}
4138 +
4139 +static HRESULT DrawImageReference(
4140 + __in THEME* pTheme,
4141 + __in const THEME_IMAGE_REFERENCE* pReference,
4142 + __in HDC hdc,
4143 + __in int destX,
4144 + __in int destY,
4145 + __in int destWidth,
4146 + __in int destHeight
4147 + )
4148 +{
4149 + HRESULT hr = S_OK;
4150 + const THEME_IMAGE_INSTANCE* pImageInstance = NULL;
4151 + int nX = 0;
4152 + int nY = 0;
4153 + int nWidth = 0;
4154 + int nHeight = 0;
4155 +
4156 + GetImageInstance(pTheme, pReference, &pImageInstance);
4157 + if (THEME_IMAGE_REFERENCE_TYPE_PARTIAL == pReference->type)
4158 + {
4159 + nX = pReference->nX;
4160 + nY = pReference->nY;
4161 + nWidth = pReference->nWidth;
4162 + nHeight = pReference->nHeight;
4163 + }
4164 + else if (THEME_IMAGE_REFERENCE_TYPE_COMPLETE == pReference->type)
4165 + {
4166 + nX = 0;
4167 + nY = 0;
4168 + nWidth = pImageInstance->pBitmap->GetWidth();
4169 + nHeight = pImageInstance->pBitmap->GetHeight();
4170 + }
4171 + else
4172 + {
4173 + AssertSz(FALSE, "Invalid image reference type for drawing");
4174 + ExitFunction1(hr = E_INVALIDARG);
4175 + }
4176 +
4177 + hr = DrawGdipBitmap(hdc, destX, destY, destWidth, destHeight, pImageInstance->pBitmap, nX, nY, nWidth, nHeight);
4178 +
4179 +LExit:
4180 + return hr;
4181 +}
4182 +
4183 static HRESULT DrawGdipBitmap(
4184 __in HDC hdc,
4185 __in int destX,
@@ -4069,36 +4242,56 @@ static HRESULT DrawProgressBar(
4242 HRESULT hr = S_OK;
4243 WORD wProgressColor = HIWORD(pControl->dwData);
4244 WORD wProgressPercentage = LOWORD(pControl->dwData);
4245 + const THEME_IMAGE_INSTANCE* pInstance = NULL;
4246 int nHeight = pdis->rcItem.bottom - pdis->rcItem.top;
4073 - int nSourceHeight = pControl->nDefaultDpiHeight;
4074 - int nSourceX = pControl->pBitmap ? 0 : pControl->nSourceX;
4075 - int nSourceY = (pControl->pBitmap ? 0 : pControl->nSourceY) + (wProgressColor * nSourceHeight);
4247 + int nSourceHeight = 0;
4248 + int nSourceX = 0;
4249 + int nSourceY = 0;
4250 int nFillableWidth = pdis->rcItem.right - 2 * nSideWidth;
4251 int nCenter = nFillableWidth > 0 ? nFillableWidth * wProgressPercentage / 100 : 0;
4078 - Gdiplus::Bitmap* pBitmap = pControl->pBitmap ? pControl->pBitmap : pTheme->pBitmap;
4252
4253 if (0 > nFillableWidth)
4254 {
4255 ExitFunction1(hr = S_FALSE);
4256 }
4257
4258 + GetImageInstance(pTheme, &pControl->imageRef, &pInstance);
4259 +
4260 + if (THEME_IMAGE_REFERENCE_TYPE_PARTIAL == pControl->imageRef.type)
4261 + {
4262 + nSourceHeight = pControl->imageRef.nHeight;
4263 + nSourceX = pControl->imageRef.nX;
4264 + nSourceY = pControl->imageRef.nY + (wProgressColor * nSourceHeight);
4265 + }
4266 + else if (THEME_IMAGE_REFERENCE_TYPE_COMPLETE == pControl->imageRef.type)
4267 + {
4268 + nSourceHeight = pControl->nDefaultDpiHeight;
4269 + nSourceX = 0;
4270 + nSourceY = wProgressColor * nSourceHeight;
4271 + }
4272 + else
4273 + {
4274 + AssertSz(FALSE, "Invalid image reference type for drawing");
4275 + ExitFunction1(hr = E_INVALIDARG);
4276 + }
4277 +
4278 // Draw the left side of the progress bar.
4086 - hr = DrawProgressBarImage(pTheme, pBitmap, nSourceX, nSourceY, 1, nSourceHeight, pdis->hDC, 0, 0, nSideWidth, nHeight);
4279 + hr = DrawProgressBarImage(pTheme, pInstance, nSourceX, nSourceY, 1, nSourceHeight, pdis->hDC, 0, 0, nSideWidth, nHeight);
4280
4281 // Draw the filled side of the progress bar, if there is any.
4282 if (0 < nCenter)
4283 {
4091 - hr = DrawProgressBarImage(pTheme, pBitmap, nSourceX + 1, nSourceY, 1, nSourceHeight, pdis->hDC, nSideWidth, 0, nCenter, nHeight);
4284 + hr = DrawProgressBarImage(pTheme, pInstance, nSourceX + 1, nSourceY, 1, nSourceHeight, pdis->hDC, nSideWidth, 0, nCenter, nHeight);
4285 }
4286
4287 // Draw the unfilled side of the progress bar, if there is any.
4288 if (nCenter < nFillableWidth)
4289 {
4097 - hr = DrawProgressBarImage(pTheme, pBitmap, nSourceX + 2, nSourceY, 1, nSourceHeight, pdis->hDC, nSideWidth + nCenter, 0, pdis->rcItem.right - nCenter - nSideWidth, nHeight);
4290 + hr = DrawProgressBarImage(pTheme, pInstance, nSourceX + 2, nSourceY, 1, nSourceHeight, pdis->hDC, nSideWidth + nCenter, 0, pdis->rcItem.right - nCenter - nSideWidth, nHeight);
4291 }
4292
4293 // Draw the right side of the progress bar.
4101 - hr = DrawProgressBarImage(pTheme, pBitmap, nSourceX + 3, nSourceY, 1, nSourceHeight, pdis->hDC, pdis->rcItem.right - nSideWidth, 0, nSideWidth, nHeight);
4294 + hr = DrawProgressBarImage(pTheme, pInstance, nSourceX + 3, nSourceY, 1, nSourceHeight, pdis->hDC, pdis->rcItem.right - nSideWidth, 0, nSideWidth, nHeight);
4295
4296 LExit:
4297 return hr;
@@ -4106,7 +4299,7 @@ LExit:
4299
4300 static HRESULT DrawProgressBarImage(
4301 __in THEME* /*pTheme*/,
4109 - __in Gdiplus::Bitmap* pBitmap,
4302 + __in const THEME_IMAGE_INSTANCE* pImageInstance,
4303 __in int srcX,
4304 __in int srcY,
4305 __in int srcWidth,
@@ -4125,7 +4318,7 @@ static HRESULT DrawProgressBarImage(
4318 graphics.SetCompositingMode(Gdiplus::CompositingMode::CompositingModeSourceCopy);
4319
4320 // Isolate the source rectangle into a temporary bitmap because otherwise GDI+ would use pixels outside of that rectangle when stretching.
4128 - Gdiplus::Status gs = graphics.DrawImage(pBitmap, dest, srcX, srcY, srcWidth, srcHeight, Gdiplus::Unit::UnitPixel);
4321 + Gdiplus::Status gs = graphics.DrawImage(pImageInstance->pBitmap, dest, srcX, srcY, srcWidth, srcHeight, Gdiplus::Unit::UnitPixel);
4322 hr = GdipHresultFromStatus(gs);
4323 if (SUCCEEDED(hr))
4324 {
@@ -4218,11 +4411,6 @@ static void FreeControl(
4411 ReleaseStr(pControl->sczValue);
4412 ReleaseStr(pControl->sczVariable);
4413
4221 - if (pControl->pBitmap)
4222 - {
4223 - delete pControl->pBitmap;
4224 - }
4225 -
4414 if (pControl->hImage)
4415 {
4416 ::DeleteBitmap(pControl->hImage);
@@ -4351,6 +4539,17 @@ static void FreeFont(
4539 }
4540
4541
4542 +static void FreeImageInstance(
4543 + __in THEME_IMAGE_INSTANCE* pImageInstance
4544 + )
4545 +{
4546 + if (pImageInstance->pBitmap)
4547 + {
4548 + delete pImageInstance->pBitmap;
4549 + }
4550 +}
4551 +
4552 +
4553 static DWORD CALLBACK RichEditStreamFromFileHandleCallback(
4554 __in DWORD_PTR dwCookie,
4555 __in_bcount(cb) LPBYTE pbBuff,
@@ -5298,6 +5497,7 @@ static HRESULT LoadControls(
5497 LPCWSTR wzWindowClass = NULL;
5498 DWORD dwWindowBits = WS_CHILD;
5499 DWORD dwWindowExBits = 0;
5500 + BOOL fOwnerDrawImage = THEME_IMAGE_REFERENCE_TYPE_NONE != pControl->imageRef.type;
5501
5502 if (fStartNewGroup)
5503 {
@@ -5322,7 +5522,7 @@ static HRESULT LoadControls(
5522 __fallthrough;
5523 case THEME_CONTROL_TYPE_BUTTON:
5524 wzWindowClass = WC_BUTTONW;
5325 - if (pControl->pBitmap || (pTheme->pBitmap && 0 <= pControl->nSourceX && 0 <= pControl->nSourceY))
5525 + if (fOwnerDrawImage)
5526 {
5527 dwWindowBits |= BS_OWNERDRAW;
5528 pControl->dwInternalStyle |= INTERNAL_CONTROL_STYLE_OWNER_DRAW;
@@ -5356,7 +5556,7 @@ static HRESULT LoadControls(
5556 break;
5557
5558 case THEME_CONTROL_TYPE_IMAGE: // images are basically just owner drawn static controls (so we can draw .jpgs and .pngs instead of just bitmaps).
5359 - if (pControl->pBitmap || (pTheme->pBitmap && 0 <= pControl->nSourceX && 0 <= pControl->nSourceY))
5559 + if (fOwnerDrawImage)
5560 {
5561 wzWindowClass = THEME_WC_STATICOWNERDRAW;
5562 dwWindowBits |= SS_OWNERDRAW;
@@ -5383,7 +5583,7 @@ static HRESULT LoadControls(
5583 break;
5584
5585 case THEME_CONTROL_TYPE_PROGRESSBAR:
5386 - if (pControl->pBitmap || (pTheme->pBitmap && 0 <= pControl->nSourceX && 0 <= pControl->nSourceY))
5586 + if (fOwnerDrawImage)
5587 {
5588 wzWindowClass = THEME_WC_STATICOWNERDRAW; // no such thing as an owner drawn progress bar so we'll make our own out of a static control.
5589 dwWindowBits |= SS_OWNERDRAW;