aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSean Hall <r.sean.hall@gmail.com>2021-06-04 13:15:28 -0500
committerSean Hall <r.sean.hall@gmail.com>2021-06-04 14:57:11 -0500
commitb22a62fd6eed5bb7a2c04d51828438daa621db6c (patch)
tree45c53dd44c2b9534f00f4bfdda5b1fa8c798ac94
parentc661b773f8ae37bbdea6da25a57d3626e7113920 (diff)
downloadwix-b22a62fd6eed5bb7a2c04d51828438daa621db6c.tar.gz
wix-b22a62fd6eed5bb7a2c04d51828438daa621db6c.tar.bz2
wix-b22a62fd6eed5bb7a2c04d51828438daa621db6c.zip
Add THEME_IMAGE_REFERENCE to thmutil.
-rw-r--r--src/libs/dutil/WixToolset.DUtil/inc/thmutil.h35
-rw-r--r--src/libs/dutil/WixToolset.DUtil/thmutil.cpp328
2 files changed, 293 insertions, 70 deletions
diff --git a/src/libs/dutil/WixToolset.DUtil/inc/thmutil.h b/src/libs/dutil/WixToolset.DUtil/inc/thmutil.h
index 32382793..2a7cabb9 100644
--- a/src/libs/dutil/WixToolset.DUtil/inc/thmutil.h
+++ b/src/libs/dutil/WixToolset.DUtil/inc/thmutil.h
@@ -75,6 +75,13 @@ typedef enum THEME_CONTROL_TYPE
75 THEME_CONTROL_TYPE_TAB, 75 THEME_CONTROL_TYPE_TAB,
76} THEME_CONTROL_TYPE; 76} THEME_CONTROL_TYPE;
77 77
78typedef 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
78typedef enum THEME_SHOW_PAGE_REASON 85typedef enum THEME_SHOW_PAGE_REASON
79{ 86{
80 THEME_SHOW_PAGE_REASON_DEFAULT, 87 THEME_SHOW_PAGE_REASON_DEFAULT,
@@ -100,6 +107,22 @@ struct THEME_COLUMN
100}; 107};
101 108
102 109
110struct 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
120struct THEME_IMAGE_INSTANCE
121{
122 Gdiplus::Bitmap* pBitmap;
123};
124
125
103struct THEME_TAB 126struct THEME_TAB
104{ 127{
105 LPWSTR pszName; 128 LPWSTR pszName;
@@ -159,15 +182,13 @@ struct THEME_CONTROL
159 int nY; 182 int nY;
160 int nHeight; 183 int nHeight;
161 int nWidth; 184 int nWidth;
162 int nSourceX;
163 int nSourceY;
164 UINT uStringId; 185 UINT uStringId;
165 186
166 LPWSTR sczEnableCondition; 187 LPWSTR sczEnableCondition;
167 LPWSTR sczVisibleCondition; 188 LPWSTR sczVisibleCondition;
168 BOOL fDisableVariableFunctionality; 189 BOOL fDisableVariableFunctionality;
169 190
170 Gdiplus::Bitmap* pBitmap; 191 THEME_IMAGE_REFERENCE imageRef;
171 HBITMAP hImage; 192 HBITMAP hImage;
172 HICON hIcon; 193 HICON hIcon;
173 194
@@ -293,15 +314,17 @@ struct THEME
293 int nMinimumWidth; 314 int nMinimumWidth;
294 int nWindowHeight; 315 int nWindowHeight;
295 int nWindowWidth; 316 int nWindowWidth;
296 int nSourceX;
297 int nSourceY;
298 UINT uStringId; 317 UINT uStringId;
299 318
300 Gdiplus::Bitmap* pBitmap; 319 DWORD dwSourceImageInstanceIndex;
320 THEME_IMAGE_REFERENCE windowImageRef;
301 321
302 DWORD cFonts; 322 DWORD cFonts;
303 THEME_FONT* rgFonts; 323 THEME_FONT* rgFonts;
304 324
325 DWORD cStandaloneImages;
326 THEME_IMAGE_INSTANCE* rgStandaloneImages;
327
305 DWORD cPages; 328 DWORD cPages;
306 THEME_PAGE* rgPages; 329 THEME_PAGE* rgPages;
307 330
diff --git a/src/libs/dutil/WixToolset.DUtil/thmutil.cpp b/src/libs/dutil/WixToolset.DUtil/thmutil.cpp
index 21460ad1..363c3be1 100644
--- a/src/libs/dutil/WixToolset.DUtil/thmutil.cpp
+++ b/src/libs/dutil/WixToolset.DUtil/thmutil.cpp
@@ -42,6 +42,7 @@
42const DWORD THEME_INVALID_ID = 0xFFFFFFFF; 42const DWORD THEME_INVALID_ID = 0xFFFFFFFF;
43const COLORREF THEME_INVISIBLE_COLORREF = 0xFFFFFFFF; 43const COLORREF THEME_INVISIBLE_COLORREF = 0xFFFFFFFF;
44const DWORD GROW_FONT_INSTANCES = 3; 44const DWORD GROW_FONT_INSTANCES = 3;
45const DWORD GROW_IMAGE_INSTANCES = 5;
45const DWORD GROW_WINDOW_TEXT = 250; 46const DWORD GROW_WINDOW_TEXT = 250;
46const LPCWSTR THEME_WC_HYPERLINK = L"ThemeHyperLink"; 47const LPCWSTR THEME_WC_HYPERLINK = L"ThemeHyperLink";
47const LPCWSTR THEME_WC_PANEL = L"ThemePanel"; 48const LPCWSTR THEME_WC_PANEL = L"ThemePanel";
@@ -87,6 +88,11 @@ static HRESULT ParseTheme(
87 __in IXMLDOMDocument* pixd, 88 __in IXMLDOMDocument* pixd,
88 __out THEME** ppTheme 89 __out THEME** ppTheme
89 ); 90 );
91static HRESULT AddStandaloneImage(
92 __in THEME* pTheme,
93 __in Gdiplus::Bitmap** ppBitmap,
94 __out DWORD* pdwIndex
95 );
90static HRESULT GetAttributeImageFileOrResource( 96static HRESULT GetAttributeImageFileOrResource(
91 __in_opt HMODULE hModule, 97 __in_opt HMODULE hModule,
92 __in_z_opt LPCWSTR wzRelativePath, 98 __in_z_opt LPCWSTR wzRelativePath,
@@ -118,9 +124,10 @@ static HRESULT GetAttributeFontId(
118 ); 124 );
119static HRESULT ParseSourceXY( 125static HRESULT ParseSourceXY(
120 __in IXMLDOMNode* pixn, 126 __in IXMLDOMNode* pixn,
121 __in BOOL fAllowed, 127 __in THEME* pTheme,
122 __inout int* pnX, 128 __in int nWidth,
123 __inout int* pnY 129 __in int nHeight,
130 __inout THEME_IMAGE_REFERENCE* pReference
124 ); 131 );
125static HRESULT ParseWindow( 132static HRESULT ParseWindow(
126 __in_opt HMODULE hModule, 133 __in_opt HMODULE hModule,
@@ -281,6 +288,20 @@ static HRESULT DrawImage(
281 __in DRAWITEMSTRUCT* pdis, 288 __in DRAWITEMSTRUCT* pdis,
282 __in const THEME_CONTROL* pControl 289 __in const THEME_CONTROL* pControl
283 ); 290 );
291static void GetImageInstance(
292 __in THEME* pTheme,
293 __in const THEME_IMAGE_REFERENCE* pReference,
294 __out const THEME_IMAGE_INSTANCE** ppInstance
295 );
296static 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 );
284static HRESULT DrawGdipBitmap( 305static HRESULT DrawGdipBitmap(
285 __in HDC hdc, 306 __in HDC hdc,
286 __in int destX, 307 __in int destX,
@@ -300,7 +321,7 @@ static HRESULT DrawProgressBar(
300 ); 321 );
301static HRESULT DrawProgressBarImage( 322static HRESULT DrawProgressBarImage(
302 __in THEME* pTheme, 323 __in THEME* pTheme,
303 __in Gdiplus::Bitmap* pBitmap, 324 __in const THEME_IMAGE_INSTANCE* pImageInstance,
304 __in int srcX, 325 __in int srcX,
305 __in int srcY, 326 __in int srcY,
306 __in int srcWidth, 327 __in int srcWidth,
@@ -333,6 +354,9 @@ static void FreeFontInstance(
333static void FreeFont( 354static void FreeFont(
334 __in THEME_FONT* pFont 355 __in THEME_FONT* pFont
335 ); 356 );
357static void FreeImageInstance(
358 __in THEME_IMAGE_INSTANCE* pImageInstance
359 );
336static void FreePage( 360static void FreePage(
337 __in THEME_PAGE* pPage 361 __in THEME_PAGE* pPage
338 ); 362 );
@@ -644,6 +668,11 @@ DAPI_(void) ThemeFree(
644 FreeFont(pTheme->rgFonts + i); 668 FreeFont(pTheme->rgFonts + i);
645 } 669 }
646 670
671 for (DWORD i = 0; i < pTheme->cStandaloneImages; ++i)
672 {
673 FreeImageInstance(pTheme->rgStandaloneImages + i);
674 }
675
647 for (DWORD i = 0; i < pTheme->cPages; ++i) 676 for (DWORD i = 0; i < pTheme->cPages; ++i)
648 { 677 {
649 FreePage(pTheme->rgPages + i); 678 FreePage(pTheme->rgPages + i);
@@ -661,13 +690,9 @@ DAPI_(void) ThemeFree(
661 690
662 ReleaseMem(pTheme->rgControls); 691 ReleaseMem(pTheme->rgControls);
663 ReleaseMem(pTheme->rgPages); 692 ReleaseMem(pTheme->rgPages);
693 ReleaseMem(pTheme->rgStandaloneImages);
664 ReleaseMem(pTheme->rgFonts); 694 ReleaseMem(pTheme->rgFonts);
665 695
666 if (pTheme->pBitmap)
667 {
668 delete pTheme->pBitmap;
669 }
670
671 ReleaseStr(pTheme->sczCaption); 696 ReleaseStr(pTheme->sczCaption);
672 ReleaseMem(pTheme); 697 ReleaseMem(pTheme);
673 } 698 }
@@ -1305,9 +1330,9 @@ DAPI_(HRESULT) ThemeDrawBackground(
1305{ 1330{
1306 HRESULT hr = S_FALSE; 1331 HRESULT hr = S_FALSE;
1307 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)
1309 { 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);
1311 } 1336 }
1312 1337
1313 return hr; 1338 return hr;
@@ -1743,6 +1768,7 @@ static HRESULT ParseTheme(
1743 HRESULT hr = S_OK; 1768 HRESULT hr = S_OK;
1744 THEME* pTheme = NULL; 1769 THEME* pTheme = NULL;
1745 IXMLDOMElement *pThemeElement = NULL; 1770 IXMLDOMElement *pThemeElement = NULL;
1771 Gdiplus::Bitmap* pBitmap = NULL;
1746 BOOL fXmlFound = FALSE; 1772 BOOL fXmlFound = FALSE;
1747 1773
1748 hr = pixd->get_documentElement(&pThemeElement); 1774 hr = pixd->get_documentElement(&pThemeElement);
@@ -1755,9 +1781,19 @@ static HRESULT ParseTheme(
1755 pTheme->nDpi = USER_DEFAULT_SCREEN_DPI; 1781 pTheme->nDpi = USER_DEFAULT_SCREEN_DPI;
1756 1782
1757 // Parse the optional background resource image. 1783 // Parse the optional background resource image.
1758 hr = GetAttributeImageFileOrResource(hModule, wzRelativePath, pThemeElement, &pTheme->pBitmap); 1784 hr = GetAttributeImageFileOrResource(hModule, wzRelativePath, pThemeElement, &pBitmap);
1759 ThmExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed while parsing theme image."); 1785 ThmExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed while parsing theme image.");
1760 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
1761 // Parse the fonts. 1797 // Parse the fonts.
1762 hr = ParseFonts(pThemeElement, pTheme); 1798 hr = ParseFonts(pThemeElement, pTheme);
1763 ThmExitOnFailure(hr, "Failed to parse theme fonts."); 1799 ThmExitOnFailure(hr, "Failed to parse theme fonts.");
@@ -1772,6 +1808,11 @@ static HRESULT ParseTheme(
1772LExit: 1808LExit:
1773 ReleaseObject(pThemeElement); 1809 ReleaseObject(pThemeElement);
1774 1810
1811 if (pBitmap)
1812 {
1813 delete pBitmap;
1814 }
1815
1775 if (pTheme) 1816 if (pTheme)
1776 { 1817 {
1777 ThemeFree(pTheme); 1818 ThemeFree(pTheme);
@@ -1780,6 +1821,30 @@ LExit:
1780 return hr; 1821 return hr;
1781} 1822}
1782 1823
1824static 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
1844LExit:
1845 return hr;
1846}
1847
1783static HRESULT GetAttributeImageFileOrResource( 1848static HRESULT GetAttributeImageFileOrResource(
1784 __in_opt HMODULE hModule, 1849 __in_opt HMODULE hModule,
1785 __in_z_opt LPCWSTR wzRelativePath, 1850 __in_z_opt LPCWSTR wzRelativePath,
@@ -1864,17 +1929,23 @@ static HRESULT ParseOwnerDrawImage(
1864 HRESULT hr = S_OK; 1929 HRESULT hr = S_OK;
1865 BOOL fXmlFound = FALSE; 1930 BOOL fXmlFound = FALSE;
1866 BOOL fFoundImage = FALSE; 1931 BOOL fFoundImage = FALSE;
1932 Gdiplus::Bitmap* pBitmap = NULL;
1867 1933
1868 // Parse the optional background resource image. 1934 // Parse the optional background resource image.
1869 hr = GetAttributeImageFileOrResource(hModule, wzRelativePath, pElement, &pControl->pBitmap); 1935 hr = GetAttributeImageFileOrResource(hModule, wzRelativePath, pElement, &pBitmap);
1870 ThmExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed while parsing control image."); 1936 ThmExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed while parsing control image.");
1871 1937
1872 if (fXmlFound) 1938 if (fXmlFound)
1873 { 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
1874 fFoundImage = TRUE; 1945 fFoundImage = TRUE;
1875 } 1946 }
1876 1947
1877 hr = ParseSourceXY(pElement, NULL != pTheme->pBitmap, &pControl->nSourceX, &pControl->nSourceY); 1948 hr = ParseSourceXY(pElement, pTheme, pControl->nWidth, pControl->nHeight, &pControl->imageRef);
1878 ThmExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to get control SourceX and SourceY attributes."); 1949 ThmExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to get control SourceX and SourceY attributes.");
1879 1950
1880 if (fXmlFound) 1951 if (fXmlFound)
@@ -1897,6 +1968,11 @@ static HRESULT ParseOwnerDrawImage(
1897 } 1968 }
1898 1969
1899LExit: 1970LExit:
1971 if (pBitmap)
1972 {
1973 delete pBitmap;
1974 }
1975
1900 return hr; 1976 return hr;
1901} 1977}
1902 1978
@@ -2042,35 +2118,50 @@ LExit:
2042 2118
2043static HRESULT ParseSourceXY( 2119static HRESULT ParseSourceXY(
2044 __in IXMLDOMNode* pixn, 2120 __in IXMLDOMNode* pixn,
2045 __in BOOL fAllowed, 2121 __in THEME* pTheme,
2046 __inout int* pnX, 2122 __in int nWidth,
2047 __inout int* pnY 2123 __in int nHeight,
2124 __inout THEME_IMAGE_REFERENCE* pReference
2048 ) 2125 )
2049{ 2126{
2050 HRESULT hr = S_OK; 2127 HRESULT hr = S_OK;
2051 BOOL fXFound = FALSE; 2128 BOOL fXFound = FALSE;
2052 BOOL fYFound = FALSE; 2129 BOOL fYFound = FALSE;
2053 2130 int nX = 0;
2054 hr = GetAttributeCoordinateOrDimension(pixn, L"SourceX", pnX); 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);
2055 ThmExitOnOptionalXmlQueryFailure(hr, fXFound, "Failed to get SourceX attribute."); 2138 ThmExitOnOptionalXmlQueryFailure(hr, fXFound, "Failed to get SourceX attribute.");
2056 2139
2057 if (!fXFound) 2140 if (!fXFound)
2058 { 2141 {
2059 *pnX = -1; 2142 nX = -1;
2060 } 2143 }
2061 else 2144 else
2062 { 2145 {
2063 if (!fAllowed) 2146 if (!pInstance)
2064 { 2147 {
2065 ThmExitWithRootFailure(hr, E_INVALIDDATA, "SourceX cannot be specified without an image specified on Theme."); 2148 ThmExitWithRootFailure(hr, E_INVALIDDATA, "SourceX cannot be specified without an image specified on Theme.");
2066 } 2149 }
2067 else if (0 > *pnX) 2150 else if (0 > nX)
2068 { 2151 {
2069 ThmExitWithRootFailure(hr, E_INVALIDDATA, "SourceX must be non-negative."); 2152 ThmExitWithRootFailure(hr, E_INVALIDDATA, "SourceX must be non-negative.");
2070 } 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 }
2071 } 2162 }
2072 2163
2073 hr = GetAttributeCoordinateOrDimension(pixn, L"SourceY", pnY); 2164 hr = GetAttributeCoordinateOrDimension(pixn, L"SourceY", &nY);
2074 ThmExitOnOptionalXmlQueryFailure(hr, fYFound, "Failed to get SourceY attribute."); 2165 ThmExitOnOptionalXmlQueryFailure(hr, fYFound, "Failed to get SourceY attribute.");
2075 2166
2076 if (!fYFound) 2167 if (!fYFound)
@@ -2080,12 +2171,11 @@ static HRESULT ParseSourceXY(
2080 ThmExitWithRootFailure(hr, E_INVALIDDATA, "SourceY must be specified with SourceX."); 2171 ThmExitWithRootFailure(hr, E_INVALIDDATA, "SourceY must be specified with SourceX.");
2081 } 2172 }
2082 2173
2083 *pnY = -1; 2174 ExitFunction1(hr = E_NOTFOUND);
2084 hr = E_NOTFOUND;
2085 } 2175 }
2086 else 2176 else
2087 { 2177 {
2088 if (!fAllowed) 2178 if (!pInstance)
2089 { 2179 {
2090 ThmExitWithRootFailure(hr, E_INVALIDDATA, "SourceY cannot be specified without an image specified on Theme."); 2180 ThmExitWithRootFailure(hr, E_INVALIDDATA, "SourceY cannot be specified without an image specified on Theme.");
2091 } 2181 }
@@ -2093,12 +2183,27 @@ static HRESULT ParseSourceXY(
2093 { 2183 {
2094 ThmExitWithRootFailure(hr, E_INVALIDDATA, "SourceY must be specified with SourceX."); 2184 ThmExitWithRootFailure(hr, E_INVALIDDATA, "SourceY must be specified with SourceX.");
2095 } 2185 }
2096 else if (0 > *pnY) 2186 else if (0 > nY)
2097 { 2187 {
2098 ThmExitWithRootFailure(hr, E_INVALIDDATA, "SourceY must be non-negative."); 2188 ThmExitWithRootFailure(hr, E_INVALIDDATA, "SourceY must be non-negative.");
2099 } 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 }
2100 } 2198 }
2101 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
2102LExit: 2207LExit:
2103 return hr; 2208 return hr;
2104} 2209}
@@ -2220,7 +2325,7 @@ static HRESULT ParseWindow(
2220 ReleaseNullBSTR(bstr); 2325 ReleaseNullBSTR(bstr);
2221 } 2326 }
2222 2327
2223 hr = ParseSourceXY(pixn, NULL != pTheme->pBitmap, &pTheme->nSourceX, &pTheme->nSourceY); 2328 hr = ParseSourceXY(pixn, pTheme, pTheme->nDefaultDpiWidth, pTheme->nDefaultDpiHeight, &pTheme->windowImageRef);
2224 ThmExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to get window SourceX and SourceY attributes."); 2329 ThmExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to get window SourceX and SourceY attributes.");
2225 2330
2226 // Parse the optional window style. 2331 // Parse the optional window style.
@@ -2230,7 +2335,7 @@ static HRESULT ParseWindow(
2230 if (!fXmlFound) 2335 if (!fXmlFound)
2231 { 2336 {
2232 pTheme->dwStyle = WS_VISIBLE | WS_MINIMIZEBOX | WS_SYSMENU | WS_CAPTION; 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;
2234 } 2339 }
2235 2340
2236 hr = XmlGetAttributeUInt32(pixn, L"StringId", reinterpret_cast<DWORD*>(&pTheme->uStringId)); 2341 hr = XmlGetAttributeUInt32(pixn, L"StringId", reinterpret_cast<DWORD*>(&pTheme->uStringId));
@@ -3171,8 +3276,6 @@ static void InitializeThemeControl(
3171 pControl->dwFontHoverId = THEME_INVALID_ID; 3276 pControl->dwFontHoverId = THEME_INVALID_ID;
3172 pControl->dwFontId = THEME_INVALID_ID; 3277 pControl->dwFontId = THEME_INVALID_ID;
3173 pControl->dwFontSelectedId = THEME_INVALID_ID; 3278 pControl->dwFontSelectedId = THEME_INVALID_ID;
3174 pControl->nSourceX = -1;
3175 pControl->nSourceY = -1;
3176 pControl->uStringId = UINT_MAX; 3279 pControl->uStringId = UINT_MAX;
3177} 3280}
3178 3281
@@ -3889,35 +3992,57 @@ static HRESULT DrawButton(
3889 ) 3992 )
3890{ 3993{
3891 HRESULT hr = S_OK; 3994 HRESULT hr = S_OK;
3892 int nSourceX = pControl->pBitmap ? 0 : pControl->nSourceX; 3995 THEME_IMAGE_REFERENCE buttonImageRef = { };
3893 int nSourceY = pControl->pBitmap ? 0 : pControl->nSourceY; 3996 const THEME_IMAGE_INSTANCE* pInstance = NULL;
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;
3897 int nHeight = pdis->rcItem.bottom - pdis->rcItem.top; 3997 int nHeight = pdis->rcItem.bottom - pdis->rcItem.top;
3898 int nWidth = pdis->rcItem.right - pdis->rcItem.left; 3998 int nWidth = pdis->rcItem.right - pdis->rcItem.left;
3899 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
3900 DWORD_PTR dwStyle = ::GetWindowLongPtrW(pdis->hwndItem, GWL_STYLE); 4024 DWORD_PTR dwStyle = ::GetWindowLongPtrW(pdis->hwndItem, GWL_STYLE);
3901 // "clicked" gets priority 4025 // "clicked" gets priority
3902 if (ODS_SELECTED & pdis->itemState) 4026 if (ODS_SELECTED & pdis->itemState)
3903 { 4027 {
3904 nSourceY += nSourceHeight * 2; 4028 buttonImageRef.nY += buttonImageRef.nHeight * 2;
3905 } 4029 }
3906 // then hover 4030 // then hover
3907 else if (pControl->dwData & THEME_CONTROL_DATA_HOVER) 4031 else if (pControl->dwData & THEME_CONTROL_DATA_HOVER)
3908 { 4032 {
3909 nSourceY += nSourceHeight; 4033 buttonImageRef.nY += buttonImageRef.nHeight;
3910 } 4034 }
3911 // then focused 4035 // then focused
3912 else if ((WS_TABSTOP & dwStyle) && (ODS_FOCUS & pdis->itemState)) 4036 else if ((WS_TABSTOP & dwStyle) && (ODS_FOCUS & pdis->itemState))
3913 { 4037 {
3914 nSourceY += nSourceHeight * 3; 4038 buttonImageRef.nY += buttonImageRef.nHeight * 3;
3915 } 4039 }
3916 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);
3918 4042
3919 DrawControlText(pTheme, pdis, pControl, TRUE, FALSE); 4043 DrawControlText(pTheme, pdis, pControl, TRUE, FALSE);
3920 4044
4045LExit:
3921 return hr; 4046 return hr;
3922} 4047}
3923 4048
@@ -3996,17 +4121,65 @@ static HRESULT DrawImage(
3996 HRESULT hr = S_OK; 4121 HRESULT hr = S_OK;
3997 int nHeight = pdis->rcItem.bottom - pdis->rcItem.top; 4122 int nHeight = pdis->rcItem.bottom - pdis->rcItem.top;
3998 int nWidth = pdis->rcItem.right - pdis->rcItem.left; 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;
4004 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);
4006 4126
4007 return hr; 4127 return hr;
4008} 4128}
4009 4129
4130static 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
4139static 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
4179LExit:
4180 return hr;
4181}
4182
4010static HRESULT DrawGdipBitmap( 4183static HRESULT DrawGdipBitmap(
4011 __in HDC hdc, 4184 __in HDC hdc,
4012 __in int destX, 4185 __in int destX,
@@ -4069,36 +4242,56 @@ static HRESULT DrawProgressBar(
4069 HRESULT hr = S_OK; 4242 HRESULT hr = S_OK;
4070 WORD wProgressColor = HIWORD(pControl->dwData); 4243 WORD wProgressColor = HIWORD(pControl->dwData);
4071 WORD wProgressPercentage = LOWORD(pControl->dwData); 4244 WORD wProgressPercentage = LOWORD(pControl->dwData);
4245 const THEME_IMAGE_INSTANCE* pInstance = NULL;
4072 int nHeight = pdis->rcItem.bottom - pdis->rcItem.top; 4246 int nHeight = pdis->rcItem.bottom - pdis->rcItem.top;
4073 int nSourceHeight = pControl->nDefaultDpiHeight; 4247 int nSourceHeight = 0;
4074 int nSourceX = pControl->pBitmap ? 0 : pControl->nSourceX; 4248 int nSourceX = 0;
4075 int nSourceY = (pControl->pBitmap ? 0 : pControl->nSourceY) + (wProgressColor * nSourceHeight); 4249 int nSourceY = 0;
4076 int nFillableWidth = pdis->rcItem.right - 2 * nSideWidth; 4250 int nFillableWidth = pdis->rcItem.right - 2 * nSideWidth;
4077 int nCenter = nFillableWidth > 0 ? nFillableWidth * wProgressPercentage / 100 : 0; 4251 int nCenter = nFillableWidth > 0 ? nFillableWidth * wProgressPercentage / 100 : 0;
4078 Gdiplus::Bitmap* pBitmap = pControl->pBitmap ? pControl->pBitmap : pTheme->pBitmap;
4079 4252
4080 if (0 > nFillableWidth) 4253 if (0 > nFillableWidth)
4081 { 4254 {
4082 ExitFunction1(hr = S_FALSE); 4255 ExitFunction1(hr = S_FALSE);
4083 } 4256 }
4084 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
4085 // Draw the left side of the progress bar. 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);
4087 4280
4088 // Draw the filled side of the progress bar, if there is any. 4281 // Draw the filled side of the progress bar, if there is any.
4089 if (0 < nCenter) 4282 if (0 < nCenter)
4090 { 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);
4092 } 4285 }
4093 4286
4094 // Draw the unfilled side of the progress bar, if there is any. 4287 // Draw the unfilled side of the progress bar, if there is any.
4095 if (nCenter < nFillableWidth) 4288 if (nCenter < nFillableWidth)
4096 { 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);
4098 } 4291 }
4099 4292
4100 // Draw the right side of the progress bar. 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);
4102 4295
4103LExit: 4296LExit:
4104 return hr; 4297 return hr;
@@ -4106,7 +4299,7 @@ LExit:
4106 4299
4107static HRESULT DrawProgressBarImage( 4300static HRESULT DrawProgressBarImage(
4108 __in THEME* /*pTheme*/, 4301 __in THEME* /*pTheme*/,
4109 __in Gdiplus::Bitmap* pBitmap, 4302 __in const THEME_IMAGE_INSTANCE* pImageInstance,
4110 __in int srcX, 4303 __in int srcX,
4111 __in int srcY, 4304 __in int srcY,
4112 __in int srcWidth, 4305 __in int srcWidth,
@@ -4125,7 +4318,7 @@ static HRESULT DrawProgressBarImage(
4125 graphics.SetCompositingMode(Gdiplus::CompositingMode::CompositingModeSourceCopy); 4318 graphics.SetCompositingMode(Gdiplus::CompositingMode::CompositingModeSourceCopy);
4126 4319
4127 // Isolate the source rectangle into a temporary bitmap because otherwise GDI+ would use pixels outside of that rectangle when stretching. 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);
4129 hr = GdipHresultFromStatus(gs); 4322 hr = GdipHresultFromStatus(gs);
4130 if (SUCCEEDED(hr)) 4323 if (SUCCEEDED(hr))
4131 { 4324 {
@@ -4218,11 +4411,6 @@ static void FreeControl(
4218 ReleaseStr(pControl->sczValue); 4411 ReleaseStr(pControl->sczValue);
4219 ReleaseStr(pControl->sczVariable); 4412 ReleaseStr(pControl->sczVariable);
4220 4413
4221 if (pControl->pBitmap)
4222 {
4223 delete pControl->pBitmap;
4224 }
4225
4226 if (pControl->hImage) 4414 if (pControl->hImage)
4227 { 4415 {
4228 ::DeleteBitmap(pControl->hImage); 4416 ::DeleteBitmap(pControl->hImage);
@@ -4351,6 +4539,17 @@ static void FreeFont(
4351} 4539}
4352 4540
4353 4541
4542static void FreeImageInstance(
4543 __in THEME_IMAGE_INSTANCE* pImageInstance
4544 )
4545{
4546 if (pImageInstance->pBitmap)
4547 {
4548 delete pImageInstance->pBitmap;
4549 }
4550}
4551
4552
4354static DWORD CALLBACK RichEditStreamFromFileHandleCallback( 4553static DWORD CALLBACK RichEditStreamFromFileHandleCallback(
4355 __in DWORD_PTR dwCookie, 4554 __in DWORD_PTR dwCookie,
4356 __in_bcount(cb) LPBYTE pbBuff, 4555 __in_bcount(cb) LPBYTE pbBuff,
@@ -5298,6 +5497,7 @@ static HRESULT LoadControls(
5298 LPCWSTR wzWindowClass = NULL; 5497 LPCWSTR wzWindowClass = NULL;
5299 DWORD dwWindowBits = WS_CHILD; 5498 DWORD dwWindowBits = WS_CHILD;
5300 DWORD dwWindowExBits = 0; 5499 DWORD dwWindowExBits = 0;
5500 BOOL fOwnerDrawImage = THEME_IMAGE_REFERENCE_TYPE_NONE != pControl->imageRef.type;
5301 5501
5302 if (fStartNewGroup) 5502 if (fStartNewGroup)
5303 { 5503 {
@@ -5322,7 +5522,7 @@ static HRESULT LoadControls(
5322 __fallthrough; 5522 __fallthrough;
5323 case THEME_CONTROL_TYPE_BUTTON: 5523 case THEME_CONTROL_TYPE_BUTTON:
5324 wzWindowClass = WC_BUTTONW; 5524 wzWindowClass = WC_BUTTONW;
5325 if (pControl->pBitmap || (pTheme->pBitmap && 0 <= pControl->nSourceX && 0 <= pControl->nSourceY)) 5525 if (fOwnerDrawImage)
5326 { 5526 {
5327 dwWindowBits |= BS_OWNERDRAW; 5527 dwWindowBits |= BS_OWNERDRAW;
5328 pControl->dwInternalStyle |= INTERNAL_CONTROL_STYLE_OWNER_DRAW; 5528 pControl->dwInternalStyle |= INTERNAL_CONTROL_STYLE_OWNER_DRAW;
@@ -5356,7 +5556,7 @@ static HRESULT LoadControls(
5356 break; 5556 break;
5357 5557
5358 case THEME_CONTROL_TYPE_IMAGE: // images are basically just owner drawn static controls (so we can draw .jpgs and .pngs instead of just bitmaps). 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)
5360 { 5560 {
5361 wzWindowClass = THEME_WC_STATICOWNERDRAW; 5561 wzWindowClass = THEME_WC_STATICOWNERDRAW;
5362 dwWindowBits |= SS_OWNERDRAW; 5562 dwWindowBits |= SS_OWNERDRAW;
@@ -5383,7 +5583,7 @@ static HRESULT LoadControls(
5383 break; 5583 break;
5384 5584
5385 case THEME_CONTROL_TYPE_PROGRESSBAR: 5585 case THEME_CONTROL_TYPE_PROGRESSBAR:
5386 if (pControl->pBitmap || (pTheme->pBitmap && 0 <= pControl->nSourceX && 0 <= pControl->nSourceY)) 5586 if (fOwnerDrawImage)
5387 { 5587 {
5388 wzWindowClass = THEME_WC_STATICOWNERDRAW; // no such thing as an owner drawn progress bar so we'll make our own out of a static control. 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.
5389 dwWindowBits |= SS_OWNERDRAW; 5589 dwWindowBits |= SS_OWNERDRAW;