aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSean Hall <r.sean.hall@gmail.com>2021-06-03 18:32:44 -0500
committerSean Hall <r.sean.hall@gmail.com>2021-06-04 14:57:11 -0500
commitc661b773f8ae37bbdea6da25a57d3626e7113920 (patch)
tree3d4dd37651f3e6e64a614ede99b55037faf79dd7 /src
parent089295bf2eb1274da2326e5864afc905070a2832 (diff)
downloadwix-c661b773f8ae37bbdea6da25a57d3626e7113920.tar.gz
wix-c661b773f8ae37bbdea6da25a57d3626e7113920.tar.bz2
wix-c661b773f8ae37bbdea6da25a57d3626e7113920.zip
In thmutil when drawing images, use GDI+ and the actual dimensions.
Partial fix for #6155 Fixes #4106
Diffstat (limited to 'src')
-rw-r--r--src/api/burn/balutil/precomp.h7
-rw-r--r--src/api/burn/test/BalUtilUnitTest/precomp.h7
-rw-r--r--src/ext/Bal/Samples/bafunctions/precomp.h2
-rw-r--r--src/libs/dutil/WixToolset.DUtil/gdiputil.cpp25
-rw-r--r--src/libs/dutil/WixToolset.DUtil/inc/gdiputil.h5
-rw-r--r--src/libs/dutil/WixToolset.DUtil/inc/thmutil.h3
-rw-r--r--src/libs/dutil/WixToolset.DUtil/thmutil.cpp307
7 files changed, 259 insertions, 97 deletions
diff --git a/src/api/burn/balutil/precomp.h b/src/api/burn/balutil/precomp.h
index 207c8ca6..15142210 100644
--- a/src/api/burn/balutil/precomp.h
+++ b/src/api/burn/balutil/precomp.h
@@ -3,6 +3,12 @@
3 3
4 4
5#include <windows.h> 5#include <windows.h>
6
7#pragma warning(push)
8#pragma warning(disable:4458) // declaration of 'xxx' hides class member
9#include <gdiplus.h>
10#pragma warning(pop)
11
6#include <bitsmsg.h> 12#include <bitsmsg.h>
7#include <msi.h> 13#include <msi.h>
8#include <wininet.h> 14#include <wininet.h>
@@ -13,6 +19,7 @@
13#include <pathutil.h> 19#include <pathutil.h>
14#include <locutil.h> 20#include <locutil.h>
15#include <memutil.h> 21#include <memutil.h>
22#include <dictutil.h>
16#include <strutil.h> 23#include <strutil.h>
17#include <thmutil.h> 24#include <thmutil.h>
18#include <xmlutil.h> 25#include <xmlutil.h>
diff --git a/src/api/burn/test/BalUtilUnitTest/precomp.h b/src/api/burn/test/BalUtilUnitTest/precomp.h
index a84391f9..f4a35e20 100644
--- a/src/api/burn/test/BalUtilUnitTest/precomp.h
+++ b/src/api/burn/test/BalUtilUnitTest/precomp.h
@@ -3,10 +3,17 @@
3 3
4 4
5#include <windows.h> 5#include <windows.h>
6
7#pragma warning(push)
8#pragma warning(disable:4458) // declaration of 'xxx' hides class member
9#include <gdiplus.h>
10#pragma warning(pop)
11
6#include <msiquery.h> 12#include <msiquery.h>
7#include <CommCtrl.h> 13#include <CommCtrl.h>
8 14
9#include <dutil.h> 15#include <dutil.h>
16#include <dictutil.h>
10#include <locutil.h> 17#include <locutil.h>
11#include <thmutil.h> 18#include <thmutil.h>
12 19
diff --git a/src/ext/Bal/Samples/bafunctions/precomp.h b/src/ext/Bal/Samples/bafunctions/precomp.h
index 9d2fe726..832d2250 100644
--- a/src/ext/Bal/Samples/bafunctions/precomp.h
+++ b/src/ext/Bal/Samples/bafunctions/precomp.h
@@ -20,7 +20,7 @@
20// Standard WiX header files, include as required 20// Standard WiX header files, include as required
21#include "dutil.h" 21#include "dutil.h"
22//#include "memutil.h" 22//#include "memutil.h"
23//#include "dictutil.h" 23#include "dictutil.h"
24//#include "dirutil.h" 24//#include "dirutil.h"
25#include "fileutil.h" 25#include "fileutil.h"
26#include "locutil.h" 26#include "locutil.h"
diff --git a/src/libs/dutil/WixToolset.DUtil/gdiputil.cpp b/src/libs/dutil/WixToolset.DUtil/gdiputil.cpp
index b5a0087c..c8b6814f 100644
--- a/src/libs/dutil/WixToolset.DUtil/gdiputil.cpp
+++ b/src/libs/dutil/WixToolset.DUtil/gdiputil.cpp
@@ -56,6 +56,7 @@ extern "C" void DAPI GdipUninitialize(
56 56
57/******************************************************************** 57/********************************************************************
58 GdipBitmapFromResource - read a GDI+ image out of a resource stream 58 GdipBitmapFromResource - read a GDI+ image out of a resource stream
59 of type RT_RCDATA.
59 60
60********************************************************************/ 61********************************************************************/
61extern "C" HRESULT DAPI GdipBitmapFromResource( 62extern "C" HRESULT DAPI GdipBitmapFromResource(
@@ -67,12 +68,13 @@ extern "C" HRESULT DAPI GdipBitmapFromResource(
67 HRESULT hr = S_OK; 68 HRESULT hr = S_OK;
68 LPVOID pvData = NULL; 69 LPVOID pvData = NULL;
69 DWORD cbData = 0; 70 DWORD cbData = 0;
70 HGLOBAL hGlobal = NULL;; 71 HGLOBAL hGlobal = NULL;
71 LPVOID pv = NULL; 72 LPVOID pv = NULL;
72 IStream *pStream = NULL; 73 IStream *pStream = NULL;
73 Bitmap *pBitmap = NULL; 74 Bitmap *pBitmap = NULL;
74 Status gs = Ok; 75 Status gs = Ok;
75 76
77 // Use ResReadData (RT_RCDATA) instead of Bitmap::FromResource (RT_BITMAP) to support all file formats that GDI+ supports.
76 hr = ResReadData(hinst, szId, &pvData, &cbData); 78 hr = ResReadData(hinst, szId, &pvData, &cbData);
77 GdipExitOnFailure(hr, "Failed to load GDI+ bitmap from resource."); 79 GdipExitOnFailure(hr, "Failed to load GDI+ bitmap from resource.");
78 80
@@ -159,6 +161,27 @@ LExit:
159} 161}
160 162
161 163
164/********************************************************************
165 GdipBitmapToGdiBitmap - convert Gdiplus::Bitmap to HBITMAP.
166
167********************************************************************/
168extern "C" HRESULT DAPI GdipBitmapToGdiBitmap(
169 __in Gdiplus::Bitmap* pBitmap,
170 __out HBITMAP* phBitmap
171 )
172{
173 HRESULT hr = S_OK;
174 Status gs = Ok;
175 Color black;
176
177 gs = pBitmap->GetHBITMAP(black, phBitmap);
178 GdipExitOnGdipFailure(gs, hr, "Failed to convert GDI+ bitmap into HBITMAP.");
179
180LExit:
181 return hr;
182}
183
184
162HRESULT DAPI GdipHresultFromStatus( 185HRESULT DAPI GdipHresultFromStatus(
163 __in Gdiplus::Status gs 186 __in Gdiplus::Status gs
164 ) 187 )
diff --git a/src/libs/dutil/WixToolset.DUtil/inc/gdiputil.h b/src/libs/dutil/WixToolset.DUtil/inc/gdiputil.h
index f2145828..6234ea64 100644
--- a/src/libs/dutil/WixToolset.DUtil/inc/gdiputil.h
+++ b/src/libs/dutil/WixToolset.DUtil/inc/gdiputil.h
@@ -30,6 +30,11 @@ HRESULT DAPI GdipBitmapFromFile(
30 __out Gdiplus::Bitmap **ppBitmap 30 __out Gdiplus::Bitmap **ppBitmap
31 ); 31 );
32 32
33HRESULT DAPI GdipBitmapToGdiBitmap(
34 __in Gdiplus::Bitmap* pBitmap,
35 __out HBITMAP* phBitmap
36 );
37
33HRESULT DAPI GdipHresultFromStatus( 38HRESULT DAPI GdipHresultFromStatus(
34 __in Gdiplus::Status gs 39 __in Gdiplus::Status gs
35 ); 40 );
diff --git a/src/libs/dutil/WixToolset.DUtil/inc/thmutil.h b/src/libs/dutil/WixToolset.DUtil/inc/thmutil.h
index d3dd6d21..32382793 100644
--- a/src/libs/dutil/WixToolset.DUtil/inc/thmutil.h
+++ b/src/libs/dutil/WixToolset.DUtil/inc/thmutil.h
@@ -167,6 +167,7 @@ struct THEME_CONTROL
167 LPWSTR sczVisibleCondition; 167 LPWSTR sczVisibleCondition;
168 BOOL fDisableVariableFunctionality; 168 BOOL fDisableVariableFunctionality;
169 169
170 Gdiplus::Bitmap* pBitmap;
170 HBITMAP hImage; 171 HBITMAP hImage;
171 HICON hIcon; 172 HICON hIcon;
172 173
@@ -296,7 +297,7 @@ struct THEME
296 int nSourceY; 297 int nSourceY;
297 UINT uStringId; 298 UINT uStringId;
298 299
299 HBITMAP hImage; 300 Gdiplus::Bitmap* pBitmap;
300 301
301 DWORD cFonts; 302 DWORD cFonts;
302 THEME_FONT* rgFonts; 303 THEME_FONT* rgFonts;
diff --git a/src/libs/dutil/WixToolset.DUtil/thmutil.cpp b/src/libs/dutil/WixToolset.DUtil/thmutil.cpp
index 1e7fa01a..21460ad1 100644
--- a/src/libs/dutil/WixToolset.DUtil/thmutil.cpp
+++ b/src/libs/dutil/WixToolset.DUtil/thmutil.cpp
@@ -91,7 +91,14 @@ static HRESULT GetAttributeImageFileOrResource(
91 __in_opt HMODULE hModule, 91 __in_opt HMODULE hModule,
92 __in_z_opt LPCWSTR wzRelativePath, 92 __in_z_opt LPCWSTR wzRelativePath,
93 __in IXMLDOMNode* pElement, 93 __in IXMLDOMNode* pElement,
94 __out HBITMAP* phImage 94 __out Gdiplus::Bitmap** ppBitmap
95 );
96static HRESULT ParseOwnerDrawImage(
97 __in_opt HMODULE hModule,
98 __in_z_opt LPCWSTR wzRelativePath,
99 __in THEME* pTheme,
100 __in IXMLDOMNode* pElement,
101 __in THEME_CONTROL* pControl
95 ); 102 );
96static HRESULT ParseCommandLinkImage( 103static HRESULT ParseCommandLinkImage(
97 __in_opt HMODULE hModule, 104 __in_opt HMODULE hModule,
@@ -274,11 +281,36 @@ static HRESULT DrawImage(
274 __in DRAWITEMSTRUCT* pdis, 281 __in DRAWITEMSTRUCT* pdis,
275 __in const THEME_CONTROL* pControl 282 __in const THEME_CONTROL* pControl
276 ); 283 );
284static HRESULT DrawGdipBitmap(
285 __in HDC hdc,
286 __in int destX,
287 __in int destY,
288 __in int destWidth,
289 __in int destHeight,
290 __in Gdiplus::Bitmap* pBitmap,
291 __in int srcX,
292 __in int srcY,
293 __in int srcWidth,
294 __in int srcHeight
295 );
277static HRESULT DrawProgressBar( 296static HRESULT DrawProgressBar(
278 __in THEME* pTheme, 297 __in THEME* pTheme,
279 __in DRAWITEMSTRUCT* pdis, 298 __in DRAWITEMSTRUCT* pdis,
280 __in const THEME_CONTROL* pControl 299 __in const THEME_CONTROL* pControl
281 ); 300 );
301static HRESULT DrawProgressBarImage(
302 __in THEME* pTheme,
303 __in Gdiplus::Bitmap* pBitmap,
304 __in int srcX,
305 __in int srcY,
306 __in int srcWidth,
307 __in int srcHeight,
308 __in HDC hdc,
309 __in int destX,
310 __in int destY,
311 __in int destWidth,
312 __in int destHeight
313 );
282static BOOL DrawHoverControl( 314static BOOL DrawHoverControl(
283 __in THEME* pTheme, 315 __in THEME* pTheme,
284 __in BOOL fHover 316 __in BOOL fHover
@@ -631,9 +663,9 @@ DAPI_(void) ThemeFree(
631 ReleaseMem(pTheme->rgPages); 663 ReleaseMem(pTheme->rgPages);
632 ReleaseMem(pTheme->rgFonts); 664 ReleaseMem(pTheme->rgFonts);
633 665
634 if (pTheme->hImage) 666 if (pTheme->pBitmap)
635 { 667 {
636 ::DeleteBitmap(pTheme->hImage); 668 delete pTheme->pBitmap;
637 } 669 }
638 670
639 ReleaseStr(pTheme->sczCaption); 671 ReleaseStr(pTheme->sczCaption);
@@ -1273,19 +1305,9 @@ DAPI_(HRESULT) ThemeDrawBackground(
1273{ 1305{
1274 HRESULT hr = S_FALSE; 1306 HRESULT hr = S_FALSE;
1275 1307
1276 if (pTheme->hImage && 0 <= pTheme->nSourceX && 0 <= pTheme->nSourceY && pps->fErase) 1308 if (pTheme->pBitmap && 0 <= pTheme->nSourceX && 0 <= pTheme->nSourceY && pps->fErase)
1277 { 1309 {
1278 HDC hdcMem = ::CreateCompatibleDC(pps->hdc); 1310 hr = DrawGdipBitmap(pps->hdc, 0, 0, pTheme->nWidth, pTheme->nHeight, pTheme->pBitmap, pTheme->nSourceX, pTheme->nSourceY, pTheme->nDefaultDpiWidth, pTheme->nDefaultDpiHeight);
1279 HBITMAP hDefaultBitmap = static_cast<HBITMAP>(::SelectObject(hdcMem, pTheme->hImage));
1280 DWORD dwSourceWidth = pTheme->nDefaultDpiWidth;
1281 DWORD dwSourceHeight = pTheme->nDefaultDpiHeight;
1282
1283 ::StretchBlt(pps->hdc, 0, 0, pTheme->nWidth, pTheme->nHeight, hdcMem, pTheme->nSourceX, pTheme->nSourceY, dwSourceWidth, dwSourceHeight, SRCCOPY);
1284
1285 ::SelectObject(hdcMem, hDefaultBitmap);
1286 ::DeleteDC(hdcMem);
1287
1288 hr = S_OK;
1289 } 1311 }
1290 1312
1291 return hr; 1313 return hr;
@@ -1733,7 +1755,7 @@ static HRESULT ParseTheme(
1733 pTheme->nDpi = USER_DEFAULT_SCREEN_DPI; 1755 pTheme->nDpi = USER_DEFAULT_SCREEN_DPI;
1734 1756
1735 // Parse the optional background resource image. 1757 // Parse the optional background resource image.
1736 hr = GetAttributeImageFileOrResource(hModule, wzRelativePath, pThemeElement, &pTheme->hImage); 1758 hr = GetAttributeImageFileOrResource(hModule, wzRelativePath, pThemeElement, &pTheme->pBitmap);
1737 ThmExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed while parsing theme image."); 1759 ThmExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed while parsing theme image.");
1738 1760
1739 // Parse the fonts. 1761 // Parse the fonts.
@@ -1762,7 +1784,7 @@ static HRESULT GetAttributeImageFileOrResource(
1762 __in_opt HMODULE hModule, 1784 __in_opt HMODULE hModule,
1763 __in_z_opt LPCWSTR wzRelativePath, 1785 __in_z_opt LPCWSTR wzRelativePath,
1764 __in IXMLDOMNode* pElement, 1786 __in IXMLDOMNode* pElement,
1765 __out HBITMAP* phImage 1787 __out Gdiplus::Bitmap** ppBitmap
1766 ) 1788 )
1767{ 1789{
1768 HRESULT hr = S_OK; 1790 HRESULT hr = S_OK;
@@ -1771,7 +1793,7 @@ static HRESULT GetAttributeImageFileOrResource(
1771 WORD wResourceId = 0; 1793 WORD wResourceId = 0;
1772 BOOL fFound = FALSE; 1794 BOOL fFound = FALSE;
1773 Gdiplus::Bitmap* pBitmap = NULL; 1795 Gdiplus::Bitmap* pBitmap = NULL;
1774 *phImage = NULL; 1796 *ppBitmap = NULL;
1775 1797
1776 hr = XmlGetAttributeUInt16(pElement, L"ImageResource", &wResourceId); 1798 hr = XmlGetAttributeUInt16(pElement, L"ImageResource", &wResourceId);
1777 ThmExitOnOptionalXmlQueryFailure(hr, fFound, "Failed to get image resource attribute."); 1799 ThmExitOnOptionalXmlQueryFailure(hr, fFound, "Failed to get image resource attribute.");
@@ -1808,12 +1830,10 @@ static HRESULT GetAttributeImageFileOrResource(
1808 ThmExitOnFailure(hr, "Failed to load image from file: %ls", sczImageFile); 1830 ThmExitOnFailure(hr, "Failed to load image from file: %ls", sczImageFile);
1809 } 1831 }
1810 1832
1811 // If there is an image, convert it into a bitmap handle.
1812 if (pBitmap) 1833 if (pBitmap)
1813 { 1834 {
1814 Gdiplus::Color black; 1835 *ppBitmap = pBitmap;
1815 Gdiplus::Status gs = pBitmap->GetHBITMAP(black, phImage); 1836 pBitmap = NULL;
1816 ThmExitOnGdipFailure(gs, hr, "Failed to convert GDI+ bitmap into HBITMAP.");
1817 } 1837 }
1818 else 1838 else
1819 { 1839 {
@@ -1846,7 +1866,7 @@ static HRESULT ParseOwnerDrawImage(
1846 BOOL fFoundImage = FALSE; 1866 BOOL fFoundImage = FALSE;
1847 1867
1848 // Parse the optional background resource image. 1868 // Parse the optional background resource image.
1849 hr = GetAttributeImageFileOrResource(hModule, wzRelativePath, pElement, &pControl->hImage); 1869 hr = GetAttributeImageFileOrResource(hModule, wzRelativePath, pElement, &pControl->pBitmap);
1850 ThmExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed while parsing control image."); 1870 ThmExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed while parsing control image.");
1851 1871
1852 if (fXmlFound) 1872 if (fXmlFound)
@@ -1854,7 +1874,7 @@ static HRESULT ParseOwnerDrawImage(
1854 fFoundImage = TRUE; 1874 fFoundImage = TRUE;
1855 } 1875 }
1856 1876
1857 hr = ParseSourceXY(pElement, NULL != pTheme->hImage, &pControl->nSourceX, &pControl->nSourceY); 1877 hr = ParseSourceXY(pElement, NULL != pTheme->pBitmap, &pControl->nSourceX, &pControl->nSourceY);
1858 ThmExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to get control SourceX and SourceY attributes."); 1878 ThmExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to get control SourceX and SourceY attributes.");
1859 1879
1860 if (fXmlFound) 1880 if (fXmlFound)
@@ -1894,10 +1914,17 @@ static HRESULT ParseCommandLinkImage(
1894 BOOL fXmlFound = FALSE; 1914 BOOL fXmlFound = FALSE;
1895 LPWSTR sczIconFile = NULL; 1915 LPWSTR sczIconFile = NULL;
1896 WORD wResourceId = 0; 1916 WORD wResourceId = 0;
1917 Gdiplus::Bitmap* pBitmap = NULL;
1897 1918
1898 hr = GetAttributeImageFileOrResource(hModule, wzRelativePath, pElement, &pControl->hImage); 1919 hr = GetAttributeImageFileOrResource(hModule, wzRelativePath, pElement, &pBitmap);
1899 ThmExitOnOptionalXmlQueryFailure(hr, fImageFound, "Failed to parse image attributes for CommandLink."); 1920 ThmExitOnOptionalXmlQueryFailure(hr, fImageFound, "Failed to parse image attributes for CommandLink.");
1900 1921
1922 if (pBitmap)
1923 {
1924 hr = GdipBitmapToGdiBitmap(pBitmap, &pControl->hImage);
1925 ThmExitOnFailure(hr, "Failed to convert bitmap for CommandLink.");
1926 }
1927
1901 hr = XmlGetAttributeUInt16(pElement, L"IconResource", &wResourceId); 1928 hr = XmlGetAttributeUInt16(pElement, L"IconResource", &wResourceId);
1902 ThmExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to get icon resource attribute."); 1929 ThmExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to get icon resource attribute.");
1903 1930
@@ -1945,6 +1972,11 @@ static HRESULT ParseCommandLinkImage(
1945 ThmExitOnUnexpectedAttribute(hr, pElement, L"CommandLink", L"SourceY"); 1972 ThmExitOnUnexpectedAttribute(hr, pElement, L"CommandLink", L"SourceY");
1946 1973
1947LExit: 1974LExit:
1975 if (pBitmap)
1976 {
1977 delete pBitmap;
1978 }
1979
1948 ReleaseStr(sczIconFile); 1980 ReleaseStr(sczIconFile);
1949 ReleaseBSTR(bstr); 1981 ReleaseBSTR(bstr);
1950 1982
@@ -2188,7 +2220,7 @@ static HRESULT ParseWindow(
2188 ReleaseNullBSTR(bstr); 2220 ReleaseNullBSTR(bstr);
2189 } 2221 }
2190 2222
2191 hr = ParseSourceXY(pixn, NULL != pTheme->hImage, &pTheme->nSourceX, &pTheme->nSourceY); 2223 hr = ParseSourceXY(pixn, NULL != pTheme->pBitmap, &pTheme->nSourceX, &pTheme->nSourceY);
2192 ThmExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to get window SourceX and SourceY attributes."); 2224 ThmExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to get window SourceX and SourceY attributes.");
2193 2225
2194 // Parse the optional window style. 2226 // Parse the optional window style.
@@ -2510,8 +2542,8 @@ static HRESULT ParseImageLists(
2510 DWORD dwImageCount = 0; 2542 DWORD dwImageCount = 0;
2511 THEME_IMAGELIST* pThemeImageList = NULL; 2543 THEME_IMAGELIST* pThemeImageList = NULL;
2512 BOOL fXmlFound = FALSE; 2544 BOOL fXmlFound = FALSE;
2513 HBITMAP hBitmap = NULL; 2545 Gdiplus::Bitmap* pBitmap = NULL;
2514 BITMAP bm = { }; 2546 HBITMAP hImage = NULL;
2515 DWORD i = 0; 2547 DWORD i = 0;
2516 int iRetVal = 0; 2548 int iRetVal = 0;
2517 2549
@@ -2551,13 +2583,18 @@ static HRESULT ParseImageLists(
2551 2583
2552 while (S_OK == (hr = XmlNextElement(pixnlImages, &pixnImage, NULL))) 2584 while (S_OK == (hr = XmlNextElement(pixnlImages, &pixnImage, NULL)))
2553 { 2585 {
2554 if (hBitmap) 2586 if (pBitmap)
2587 {
2588 delete pBitmap;
2589 pBitmap = NULL;
2590 }
2591 if (hImage)
2555 { 2592 {
2556 ::DeleteObject(hBitmap); 2593 ::DeleteObject(hImage);
2557 hBitmap = NULL; 2594 hImage = NULL;
2558 } 2595 }
2559 2596
2560 hr = GetAttributeImageFileOrResource(hModule, wzRelativePath, pixnImage, &hBitmap); 2597 hr = GetAttributeImageFileOrResource(hModule, wzRelativePath, pixnImage, &pBitmap);
2561 ThmExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to parse image list: '%ls', item: %u", pThemeImageList->sczName, i); 2598 ThmExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to parse image list: '%ls', item: %u", pThemeImageList->sczName, i);
2562 2599
2563 if (!fXmlFound) 2600 if (!fXmlFound)
@@ -2567,13 +2604,14 @@ static HRESULT ParseImageLists(
2567 2604
2568 if (0 == i) 2605 if (0 == i)
2569 { 2606 {
2570 ::GetObjectW(hBitmap, sizeof(BITMAP), &bm); 2607 pThemeImageList->hImageList = ImageList_Create(pBitmap->GetWidth(), pBitmap->GetHeight(), ILC_COLOR24, dwImageCount, 0);
2571
2572 pThemeImageList->hImageList = ImageList_Create(bm.bmWidth, bm.bmHeight, ILC_COLOR24, dwImageCount, 0);
2573 ThmExitOnNullWithLastError(pThemeImageList->hImageList, hr, "Failed to create image list."); 2608 ThmExitOnNullWithLastError(pThemeImageList->hImageList, hr, "Failed to create image list.");
2574 } 2609 }
2575 2610
2576 iRetVal = ImageList_Add(pThemeImageList->hImageList, hBitmap, NULL); 2611 hr = GdipBitmapToGdiBitmap(pBitmap, &hImage);
2612 ThmExitOnFailure(hr, "Failed to convert bitmap for CommandLink.");
2613
2614 iRetVal = ImageList_Add(pThemeImageList->hImageList, hImage, NULL);
2577 if (-1 == iRetVal) 2615 if (-1 == iRetVal)
2578 { 2616 {
2579 ThmExitWithLastError(hr, "Failed to add image %u to image list.", i); 2617 ThmExitWithLastError(hr, "Failed to add image %u to image list.", i);
@@ -2588,9 +2626,13 @@ static HRESULT ParseImageLists(
2588 } 2626 }
2589 2627
2590LExit: 2628LExit:
2591 if (hBitmap) 2629 if (hImage)
2592 { 2630 {
2593 ::DeleteObject(hBitmap); 2631 ::DeleteObject(hImage);
2632 }
2633 if (pBitmap)
2634 {
2635 delete pBitmap;
2594 } 2636 }
2595 ReleaseObject(pixnlImageLists); 2637 ReleaseObject(pixnlImageLists);
2596 ReleaseObject(pixnImageList); 2638 ReleaseObject(pixnImageList);
@@ -3846,39 +3888,37 @@ static HRESULT DrawButton(
3846 __in const THEME_CONTROL* pControl 3888 __in const THEME_CONTROL* pControl
3847 ) 3889 )
3848{ 3890{
3849 int nSourceX = pControl->hImage ? 0 : pControl->nSourceX; 3891 HRESULT hr = S_OK;
3850 int nSourceY = pControl->hImage ? 0 : pControl->nSourceY; 3892 int nSourceX = pControl->pBitmap ? 0 : pControl->nSourceX;
3851 DWORD dwSourceWidth = pControl->nDefaultDpiWidth; 3893 int nSourceY = pControl->pBitmap ? 0 : pControl->nSourceY;
3852 DWORD dwSourceHeight = pControl->nDefaultDpiHeight; 3894 int nSourceWidth = pControl->pBitmap ? pControl->pBitmap->GetWidth() : pControl->nDefaultDpiWidth;
3853 3895 int nSourceHeight = pControl->pBitmap ? pControl->pBitmap->GetHeight() / 4 : pControl->nDefaultDpiHeight;
3854 HDC hdcMem = ::CreateCompatibleDC(pdis->hDC); 3896 Gdiplus::Bitmap* pBitmap = pControl->pBitmap ? pControl->pBitmap : pTheme->pBitmap;
3855 HBITMAP hDefaultBitmap = static_cast<HBITMAP>(::SelectObject(hdcMem, pControl->hImage ? pControl->hImage : pTheme->hImage)); 3897 int nHeight = pdis->rcItem.bottom - pdis->rcItem.top;
3898 int nWidth = pdis->rcItem.right - pdis->rcItem.left;
3856 3899
3857 DWORD_PTR dwStyle = ::GetWindowLongPtrW(pdis->hwndItem, GWL_STYLE); 3900 DWORD_PTR dwStyle = ::GetWindowLongPtrW(pdis->hwndItem, GWL_STYLE);
3858 // "clicked" gets priority 3901 // "clicked" gets priority
3859 if (ODS_SELECTED & pdis->itemState) 3902 if (ODS_SELECTED & pdis->itemState)
3860 { 3903 {
3861 nSourceY += pControl->nDefaultDpiHeight * 2; 3904 nSourceY += nSourceHeight * 2;
3862 } 3905 }
3863 // then hover 3906 // then hover
3864 else if (pControl->dwData & THEME_CONTROL_DATA_HOVER) 3907 else if (pControl->dwData & THEME_CONTROL_DATA_HOVER)
3865 { 3908 {
3866 nSourceY += pControl->nDefaultDpiHeight; 3909 nSourceY += nSourceHeight;
3867 } 3910 }
3868 // then focused 3911 // then focused
3869 else if (WS_TABSTOP & dwStyle && ODS_FOCUS & pdis->itemState) 3912 else if ((WS_TABSTOP & dwStyle) && (ODS_FOCUS & pdis->itemState))
3870 { 3913 {
3871 nSourceY += pControl->nDefaultDpiHeight * 3; 3914 nSourceY += nSourceHeight * 3;
3872 } 3915 }
3873 3916
3874 ::StretchBlt(pdis->hDC, 0, 0, pControl->nWidth, pControl->nHeight, hdcMem, nSourceX, nSourceY, dwSourceWidth, dwSourceHeight, SRCCOPY); 3917 hr = DrawGdipBitmap(pdis->hDC, 0, 0, nWidth, nHeight, pBitmap, nSourceX, nSourceY, nSourceWidth, nSourceHeight);
3875
3876 ::SelectObject(hdcMem, hDefaultBitmap);
3877 ::DeleteDC(hdcMem);
3878 3918
3879 DrawControlText(pTheme, pdis, pControl, TRUE, FALSE); 3919 DrawControlText(pTheme, pdis, pControl, TRUE, FALSE);
3880 3920
3881 return S_OK; 3921 return hr;
3882} 3922}
3883 3923
3884 3924
@@ -3953,31 +3993,69 @@ static HRESULT DrawImage(
3953 __in const THEME_CONTROL* pControl 3993 __in const THEME_CONTROL* pControl
3954 ) 3994 )
3955{ 3995{
3956 DWORD dwHeight = pdis->rcItem.bottom - pdis->rcItem.top; 3996 HRESULT hr = S_OK;
3957 DWORD dwWidth = pdis->rcItem.right - pdis->rcItem.left; 3997 int nHeight = pdis->rcItem.bottom - pdis->rcItem.top;
3958 int nSourceX = pControl->hImage ? 0 : pControl->nSourceX; 3998 int nWidth = pdis->rcItem.right - pdis->rcItem.left;
3959 int nSourceY = pControl->hImage ? 0 : pControl->nSourceY; 3999 int nSourceX = pControl->pBitmap ? 0 : pControl->nSourceX;
3960 DWORD dwSourceHeight = pControl->nDefaultDpiHeight; 4000 int nSourceY = pControl->pBitmap ? 0 : pControl->nSourceY;
3961 DWORD dwSourceWidth = pControl->nDefaultDpiWidth; 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
4005 hr = DrawGdipBitmap(pdis->hDC, 0, 0, nWidth, nHeight, pBitmap, nSourceX, nSourceY, nSourceWidth, nSourceHeight);
4006
4007 return hr;
4008}
3962 4009
3963 BLENDFUNCTION bf = { }; 4010static HRESULT DrawGdipBitmap(
3964 bf.BlendOp = AC_SRC_OVER; 4011 __in HDC hdc,
3965 bf.SourceConstantAlpha = 255; 4012 __in int destX,
3966 bf.AlphaFormat = AC_SRC_ALPHA; 4013 __in int destY,
4014 __in int destWidth,
4015 __in int destHeight,
4016 __in Gdiplus::Bitmap* pBitmap,
4017 __in int srcX,
4018 __in int srcY,
4019 __in int srcWidth,
4020 __in int srcHeight
4021 )
4022{
4023 // Note that this only indicates that GDI+ supports transparency from the source image type.
4024 // Bitmaps with alpha information will return FALSE, while fully opaque PNGs will return TRUE.
4025 BOOL fTransparency = (pBitmap->GetFlags() & Gdiplus::ImageFlagsHasAlpha) == Gdiplus::ImageFlagsHasAlpha;
4026 Gdiplus::ImageAttributes attrs;
4027 Gdiplus::Rect destRect(destX, destY, destWidth, destHeight);
4028 Gdiplus::Graphics graphics(hdc);
4029 Gdiplus::Status gs = Gdiplus::Status::Ok;
3967 4030
3968 HDC hdcMem = ::CreateCompatibleDC(pdis->hDC); 4031 // This fixes GDI+ behavior where it badly handles the edges of an image when scaling.
3969 HBITMAP hDefaultBitmap = static_cast<HBITMAP>(::SelectObject(hdcMem, pControl->hImage ? pControl->hImage : pTheme->hImage)); 4032 // This is easily seen when using an image Progressbar that's 4x1 - the progress bar fades to transparent in both directions.
4033 attrs.SetWrapMode(Gdiplus::WrapMode::WrapModeTileFlipXY);
3970 4034
3971 // Try to draw the image with transparency and if that fails (usually because the image has no 4035 // graphics.SmoothingMode is not set because it has no impact on DrawImage.
3972 // alpha channel) then draw the image as is. 4036
3973 if (!::AlphaBlend(pdis->hDC, 0, 0, dwWidth, dwHeight, hdcMem, nSourceX, nSourceY, dwSourceWidth, dwSourceHeight, bf)) 4037 // This is the best interpolation mode, and the only one that is decent at downscaling.
4038 graphics.SetInterpolationMode(Gdiplus::InterpolationMode::InterpolationModeHighQualityBicubic);
4039
4040 // There's a significant quality improvement when scaling to use the HighQuality pixel offset mode with no measurable difference in performance.
4041 graphics.SetPixelOffsetMode(Gdiplus::PixelOffsetMode::PixelOffsetModeHighQuality);
4042
4043 // If there's transparency, make sure that the blending is done with high quality.
4044 // If not, try to skip blending.
4045 if (fTransparency)
3974 { 4046 {
3975 ::StretchBlt(pdis->hDC, 0, 0, dwWidth, dwHeight, hdcMem, nSourceX, nSourceY, dwSourceWidth, dwSourceHeight, SRCCOPY); 4047 graphics.SetCompositingMode(Gdiplus::CompositingMode::CompositingModeSourceOver);
4048 graphics.SetCompositingQuality(Gdiplus::CompositingQuality::CompositingQualityHighQuality);
4049 }
4050 else
4051 {
4052 graphics.SetCompositingMode(Gdiplus::CompositingMode::CompositingModeSourceCopy);
4053 graphics.SetCompositingQuality(Gdiplus::CompositingQuality::CompositingQualityHighSpeed);
3976 } 4054 }
3977 4055
3978 ::SelectObject(hdcMem, hDefaultBitmap); 4056 gs = graphics.DrawImage(pBitmap, destRect, srcX, srcY, srcWidth, srcHeight, Gdiplus::Unit::UnitPixel, &attrs);
3979 ::DeleteDC(hdcMem); 4057
3980 return S_OK; 4058 return GdipHresultFromStatus(gs);
3981} 4059}
3982 4060
3983 4061
@@ -3987,38 +4065,74 @@ static HRESULT DrawProgressBar(
3987 __in const THEME_CONTROL* pControl 4065 __in const THEME_CONTROL* pControl
3988 ) 4066 )
3989{ 4067{
3990 DWORD dwProgressColor = HIWORD(pControl->dwData); 4068 const int nSideWidth = 1;
3991 DWORD dwProgressPercentage = LOWORD(pControl->dwData); 4069 HRESULT hr = S_OK;
3992 DWORD dwHeight = pdis->rcItem.bottom - pdis->rcItem.top; 4070 WORD wProgressColor = HIWORD(pControl->dwData);
3993 DWORD dwCenter = (pdis->rcItem.right - 2) * dwProgressPercentage / 100; 4071 WORD wProgressPercentage = LOWORD(pControl->dwData);
3994 DWORD dwSourceHeight = pControl->nDefaultDpiHeight; 4072 int nHeight = pdis->rcItem.bottom - pdis->rcItem.top;
3995 int nSourceX = pControl->hImage ? 0 : pControl->nSourceX; 4073 int nSourceHeight = pControl->nDefaultDpiHeight;
3996 int nSourceY = (pControl->hImage ? 0 : pControl->nSourceY) + (dwProgressColor * dwSourceHeight); 4074 int nSourceX = pControl->pBitmap ? 0 : pControl->nSourceX;
4075 int nSourceY = (pControl->pBitmap ? 0 : pControl->nSourceY) + (wProgressColor * nSourceHeight);
4076 int nFillableWidth = pdis->rcItem.right - 2 * nSideWidth;
4077 int nCenter = nFillableWidth > 0 ? nFillableWidth * wProgressPercentage / 100 : 0;
4078 Gdiplus::Bitmap* pBitmap = pControl->pBitmap ? pControl->pBitmap : pTheme->pBitmap;
3997 4079
3998 HDC hdcMem = ::CreateCompatibleDC(pdis->hDC); 4080 if (0 > nFillableWidth)
3999 HBITMAP hDefaultBitmap = static_cast<HBITMAP>(::SelectObject(hdcMem, pControl->hImage ? pControl->hImage : pTheme->hImage)); 4081 {
4082 ExitFunction1(hr = S_FALSE);
4083 }
4000 4084
4001 // Draw the left side of the progress bar. 4085 // Draw the left side of the progress bar.
4002 ::StretchBlt(pdis->hDC, 0, 0, 1, dwHeight, hdcMem, nSourceX, nSourceY, 1, dwSourceHeight, SRCCOPY); 4086 hr = DrawProgressBarImage(pTheme, pBitmap, nSourceX, nSourceY, 1, nSourceHeight, pdis->hDC, 0, 0, nSideWidth, nHeight);
4003 4087
4004 // Draw the filled side of the progress bar, if there is any. 4088 // Draw the filled side of the progress bar, if there is any.
4005 if (0 < dwCenter) 4089 if (0 < nCenter)
4006 { 4090 {
4007 ::StretchBlt(pdis->hDC, 1, 0, dwCenter, dwHeight, hdcMem, nSourceX + 1, nSourceY, 1, dwSourceHeight, SRCCOPY); 4091 hr = DrawProgressBarImage(pTheme, pBitmap, nSourceX + 1, nSourceY, 1, nSourceHeight, pdis->hDC, nSideWidth, 0, nCenter, nHeight);
4008 } 4092 }
4009 4093
4010 // Draw the unfilled side of the progress bar, if there is any. 4094 // Draw the unfilled side of the progress bar, if there is any.
4011 if (dwCenter < static_cast<DWORD>(pdis->rcItem.right - 2)) 4095 if (nCenter < nFillableWidth)
4012 { 4096 {
4013 ::StretchBlt(pdis->hDC, 1 + dwCenter, 0, pdis->rcItem.right - dwCenter - 1, dwHeight, hdcMem, nSourceX + 2, nSourceY, 1, dwSourceHeight, SRCCOPY); 4097 hr = DrawProgressBarImage(pTheme, pBitmap, nSourceX + 2, nSourceY, 1, nSourceHeight, pdis->hDC, nSideWidth + nCenter, 0, pdis->rcItem.right - nCenter - nSideWidth, nHeight);
4014 } 4098 }
4015 4099
4016 // Draw the right side of the progress bar. 4100 // Draw the right side of the progress bar.
4017 ::StretchBlt(pdis->hDC, pdis->rcItem.right - 1, 0, 1, dwHeight, hdcMem, nSourceX + 3, nSourceY, 1, dwSourceHeight, SRCCOPY); 4101 hr = DrawProgressBarImage(pTheme, pBitmap, nSourceX + 3, nSourceY, 1, nSourceHeight, pdis->hDC, pdis->rcItem.right - nSideWidth, 0, nSideWidth, nHeight);
4018 4102
4019 ::SelectObject(hdcMem, hDefaultBitmap); 4103LExit:
4020 ::DeleteDC(hdcMem); 4104 return hr;
4021 return S_OK; 4105}
4106
4107static HRESULT DrawProgressBarImage(
4108 __in THEME* /*pTheme*/,
4109 __in Gdiplus::Bitmap* pBitmap,
4110 __in int srcX,
4111 __in int srcY,
4112 __in int srcWidth,
4113 __in int srcHeight,
4114 __in HDC hdc,
4115 __in int destX,
4116 __in int destY,
4117 __in int destWidth,
4118 __in int destHeight
4119 )
4120{
4121 HRESULT hr = S_OK;
4122 Gdiplus::Rect dest(0, 0, srcWidth, srcHeight);
4123 Gdiplus::Bitmap isolated(dest.Width, dest.Height);
4124 Gdiplus::Graphics graphics(&isolated);
4125 graphics.SetCompositingMode(Gdiplus::CompositingMode::CompositingModeSourceCopy);
4126
4127 // 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);
4129 hr = GdipHresultFromStatus(gs);
4130 if (SUCCEEDED(hr))
4131 {
4132 hr = DrawGdipBitmap(hdc, destX, destY, destWidth, destHeight, &isolated, 0, 0, isolated.GetWidth(), isolated.GetHeight());
4133 }
4134
4135 return hr;
4022} 4136}
4023 4137
4024 4138
@@ -4104,6 +4218,11 @@ static void FreeControl(
4104 ReleaseStr(pControl->sczValue); 4218 ReleaseStr(pControl->sczValue);
4105 ReleaseStr(pControl->sczVariable); 4219 ReleaseStr(pControl->sczVariable);
4106 4220
4221 if (pControl->pBitmap)
4222 {
4223 delete pControl->pBitmap;
4224 }
4225
4107 if (pControl->hImage) 4226 if (pControl->hImage)
4108 { 4227 {
4109 ::DeleteBitmap(pControl->hImage); 4228 ::DeleteBitmap(pControl->hImage);
@@ -5203,7 +5322,7 @@ static HRESULT LoadControls(
5203 __fallthrough; 5322 __fallthrough;
5204 case THEME_CONTROL_TYPE_BUTTON: 5323 case THEME_CONTROL_TYPE_BUTTON:
5205 wzWindowClass = WC_BUTTONW; 5324 wzWindowClass = WC_BUTTONW;
5206 if (pControl->hImage || (pTheme->hImage && 0 <= pControl->nSourceX && 0 <= pControl->nSourceY)) 5325 if (pControl->pBitmap || (pTheme->pBitmap && 0 <= pControl->nSourceX && 0 <= pControl->nSourceY))
5207 { 5326 {
5208 dwWindowBits |= BS_OWNERDRAW; 5327 dwWindowBits |= BS_OWNERDRAW;
5209 pControl->dwInternalStyle |= INTERNAL_CONTROL_STYLE_OWNER_DRAW; 5328 pControl->dwInternalStyle |= INTERNAL_CONTROL_STYLE_OWNER_DRAW;
@@ -5237,7 +5356,7 @@ static HRESULT LoadControls(
5237 break; 5356 break;
5238 5357
5239 case THEME_CONTROL_TYPE_IMAGE: // images are basically just owner drawn static controls (so we can draw .jpgs and .pngs instead of just bitmaps). 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).
5240 if (pControl->hImage || (pTheme->hImage && 0 <= pControl->nSourceX && 0 <= pControl->nSourceY)) 5359 if (pControl->pBitmap || (pTheme->pBitmap && 0 <= pControl->nSourceX && 0 <= pControl->nSourceY))
5241 { 5360 {
5242 wzWindowClass = THEME_WC_STATICOWNERDRAW; 5361 wzWindowClass = THEME_WC_STATICOWNERDRAW;
5243 dwWindowBits |= SS_OWNERDRAW; 5362 dwWindowBits |= SS_OWNERDRAW;
@@ -5264,7 +5383,7 @@ static HRESULT LoadControls(
5264 break; 5383 break;
5265 5384
5266 case THEME_CONTROL_TYPE_PROGRESSBAR: 5385 case THEME_CONTROL_TYPE_PROGRESSBAR:
5267 if (pControl->hImage || (pTheme->hImage && 0 <= pControl->nSourceX && 0 <= pControl->nSourceY)) 5386 if (pControl->pBitmap || (pTheme->pBitmap && 0 <= pControl->nSourceX && 0 <= pControl->nSourceY))
5268 { 5387 {
5269 wzWindowClass = THEME_WC_STATICOWNERDRAW; // no such thing as an owner drawn progress bar so we'll make our own out of a static control. 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.
5270 dwWindowBits |= SS_OWNERDRAW; 5389 dwWindowBits |= SS_OWNERDRAW;