aboutsummaryrefslogtreecommitdiff
path: root/src/libs/dutil
diff options
context:
space:
mode:
authorSean Hall <r.sean.hall@gmail.com>2021-06-04 13:37:30 -0500
committerSean Hall <r.sean.hall@gmail.com>2021-06-04 14:57:11 -0500
commit700b48c723531bfc38bab185f237d932144f3b26 (patch)
tree0a7acc65b0de9f47e6b2d2fa3a2994809cfcbfa6 /src/libs/dutil
parent34639850c2c07a35c1e502e174866cd8630eb8ec (diff)
downloadwix-700b48c723531bfc38bab185f237d932144f3b26.tar.gz
wix-700b48c723531bfc38bab185f237d932144f3b26.tar.bz2
wix-700b48c723531bfc38bab185f237d932144f3b26.zip
Add thmutil Image element to allow specifying multiple resolutions.
Rename previous Image element to ImageListItem. Last partial fix for #6155
Diffstat (limited to 'src/libs/dutil')
-rw-r--r--src/libs/dutil/WixToolset.DUtil/inc/thmutil.h14
-rw-r--r--src/libs/dutil/WixToolset.DUtil/thmutil.cpp382
2 files changed, 371 insertions, 25 deletions
diff --git a/src/libs/dutil/WixToolset.DUtil/inc/thmutil.h b/src/libs/dutil/WixToolset.DUtil/inc/thmutil.h
index c8c6b340..6ac3711f 100644
--- a/src/libs/dutil/WixToolset.DUtil/inc/thmutil.h
+++ b/src/libs/dutil/WixToolset.DUtil/inc/thmutil.h
@@ -110,6 +110,7 @@ struct THEME_COLUMN
110struct THEME_IMAGE_REFERENCE 110struct THEME_IMAGE_REFERENCE
111{ 111{
112 THEME_IMAGE_REFERENCE_TYPE type; 112 THEME_IMAGE_REFERENCE_TYPE type;
113 DWORD dwImageIndex;
113 DWORD dwImageInstanceIndex; 114 DWORD dwImageInstanceIndex;
114 int nX; 115 int nX;
115 int nY; 116 int nY;
@@ -122,6 +123,15 @@ struct THEME_IMAGE_INSTANCE
122 Gdiplus::Bitmap* pBitmap; 123 Gdiplus::Bitmap* pBitmap;
123}; 124};
124 125
126struct THEME_IMAGE
127{
128 LPWSTR sczId;
129 DWORD dwIndex;
130
131 DWORD cImageInstances;
132 THEME_IMAGE_INSTANCE* rgImageInstances;
133};
134
125 135
126struct THEME_TAB 136struct THEME_TAB
127{ 137{
@@ -342,6 +352,9 @@ struct THEME
342 DWORD cFonts; 352 DWORD cFonts;
343 THEME_FONT* rgFonts; 353 THEME_FONT* rgFonts;
344 354
355 DWORD cImages;
356 THEME_IMAGE* rgImages;
357
345 DWORD cStandaloneImages; 358 DWORD cStandaloneImages;
346 THEME_IMAGE_INSTANCE* rgStandaloneImages; 359 THEME_IMAGE_INSTANCE* rgStandaloneImages;
347 360
@@ -356,6 +369,7 @@ struct THEME
356 369
357 // internal state variables -- do not use outside ThmUtil.cpp 370 // internal state variables -- do not use outside ThmUtil.cpp
358 STRINGDICT_HANDLE sdhFontDictionary; 371 STRINGDICT_HANDLE sdhFontDictionary;
372 STRINGDICT_HANDLE sdhImageDictionary;
359 HWND hwndParent; // parent for loaded controls 373 HWND hwndParent; // parent for loaded controls
360 HWND hwndHover; // current hwnd hovered over 374 HWND hwndHover; // current hwnd hovered over
361 DWORD dwCurrentPageId; 375 DWORD dwCurrentPageId;
diff --git a/src/libs/dutil/WixToolset.DUtil/thmutil.cpp b/src/libs/dutil/WixToolset.DUtil/thmutil.cpp
index ab320b1d..1e0051d4 100644
--- a/src/libs/dutil/WixToolset.DUtil/thmutil.cpp
+++ b/src/libs/dutil/WixToolset.DUtil/thmutil.cpp
@@ -139,6 +139,12 @@ static HRESULT GetAttributeFontId(
139 __in LPCWSTR wzAttribute, 139 __in LPCWSTR wzAttribute,
140 __inout DWORD* pdwValue 140 __inout DWORD* pdwValue
141 ); 141 );
142static HRESULT GetAttributeImageId(
143 __in THEME* pTheme,
144 __in IXMLDOMNode* pixn,
145 __in LPCWSTR wzAttribute,
146 __inout DWORD* pdwValue
147 );
142static HRESULT ParseSourceXY( 148static HRESULT ParseSourceXY(
143 __in IXMLDOMNode* pixn, 149 __in IXMLDOMNode* pixn,
144 __in THEME* pTheme, 150 __in THEME* pTheme,
@@ -162,6 +168,12 @@ static HRESULT ParseFonts(
162 __in IXMLDOMElement* pElement, 168 __in IXMLDOMElement* pElement,
163 __in THEME* pTheme 169 __in THEME* pTheme
164 ); 170 );
171static HRESULT ParseImages(
172 __in_opt HMODULE hModule,
173 __in_opt LPCWSTR wzRelativePath,
174 __in IXMLDOMElement* pElement,
175 __in THEME* pTheme
176 );
165static HRESULT ParsePages( 177static HRESULT ParsePages(
166 __in_opt HMODULE hModule, 178 __in_opt HMODULE hModule,
167 __in_opt LPCWSTR wzRelativePath, 179 __in_opt LPCWSTR wzRelativePath,
@@ -371,6 +383,9 @@ static void FreeFontInstance(
371static void FreeFont( 383static void FreeFont(
372 __in THEME_FONT* pFont 384 __in THEME_FONT* pFont
373 ); 385 );
386static void FreeImage(
387 __in THEME_IMAGE* pImage
388 );
374static void FreeImageInstance( 389static void FreeImageInstance(
375 __in THEME_IMAGE_INSTANCE* pImageInstance 390 __in THEME_IMAGE_INSTANCE* pImageInstance
376 ); 391 );
@@ -486,11 +501,13 @@ static HRESULT LoadControlString(
486 __in HMODULE hResModule 501 __in HMODULE hResModule
487 ); 502 );
488static void ResizeControls( 503static void ResizeControls(
504 __in THEME* pTheme,
489 __in DWORD cControls, 505 __in DWORD cControls,
490 __in THEME_CONTROL* rgControls, 506 __in THEME_CONTROL* rgControls,
491 __in const RECT* prcParent 507 __in const RECT* prcParent
492 ); 508 );
493static void ResizeControl( 509static void ResizeControl(
510 __in THEME* pTheme,
494 __in THEME_CONTROL* pControl, 511 __in THEME_CONTROL* pControl,
495 __in const RECT* prcParent 512 __in const RECT* prcParent
496 ); 513 );
@@ -532,6 +549,12 @@ static void GetControls(
532 __out DWORD& cControls, 549 __out DWORD& cControls,
533 __out THEME_CONTROL*& rgControls 550 __out THEME_CONTROL*& rgControls
534 ); 551 );
552static void ScaleImageReference(
553 __in THEME* pTheme,
554 __in THEME_IMAGE_REFERENCE* pImageRef,
555 __in int nDestWidth,
556 __in int nDestHeight
557 );
535static void UnloadControls( 558static void UnloadControls(
536 __in DWORD cControls, 559 __in DWORD cControls,
537 __in THEME_CONTROL* rgControls 560 __in THEME_CONTROL* rgControls
@@ -685,6 +708,11 @@ DAPI_(void) ThemeFree(
685 FreeFont(pTheme->rgFonts + i); 708 FreeFont(pTheme->rgFonts + i);
686 } 709 }
687 710
711 for (DWORD i = 0; i < pTheme->cImages; ++i)
712 {
713 FreeImage(pTheme->rgImages + i);
714 }
715
688 for (DWORD i = 0; i < pTheme->cStandaloneImages; ++i) 716 for (DWORD i = 0; i < pTheme->cStandaloneImages; ++i)
689 { 717 {
690 FreeImageInstance(pTheme->rgStandaloneImages + i); 718 FreeImageInstance(pTheme->rgStandaloneImages + i);
@@ -708,10 +736,12 @@ DAPI_(void) ThemeFree(
708 ReleaseMem(pTheme->rgControls); 736 ReleaseMem(pTheme->rgControls);
709 ReleaseMem(pTheme->rgPages); 737 ReleaseMem(pTheme->rgPages);
710 ReleaseMem(pTheme->rgStandaloneImages); 738 ReleaseMem(pTheme->rgStandaloneImages);
739 ReleaseMem(pTheme->rgImages);
711 ReleaseMem(pTheme->rgFonts); 740 ReleaseMem(pTheme->rgFonts);
712 741
713 ReleaseStr(pTheme->sczCaption); 742 ReleaseStr(pTheme->sczCaption);
714 ReleaseDict(pTheme->sdhFontDictionary); 743 ReleaseDict(pTheme->sdhFontDictionary);
744 ReleaseDict(pTheme->sdhImageDictionary);
715 ReleaseMem(pTheme); 745 ReleaseMem(pTheme);
716 } 746 }
717} 747}
@@ -1063,7 +1093,8 @@ extern "C" LRESULT CALLBACK ThemeDefWindowProc(
1063 { 1093 {
1064 pTheme->fForceResize = FALSE; 1094 pTheme->fForceResize = FALSE;
1065 ::GetClientRect(pTheme->hwndParent, &rcParent); 1095 ::GetClientRect(pTheme->hwndParent, &rcParent);
1066 ResizeControls(pTheme->cControls, pTheme->rgControls, &rcParent); 1096 ScaleImageReference(pTheme, &pTheme->windowImageRef, rcParent.right - rcParent.left, rcParent.bottom - rcParent.top);
1097 ResizeControls(pTheme, pTheme->cControls, pTheme->rgControls, &rcParent);
1067 return 0; 1098 return 0;
1068 } 1099 }
1069 break; 1100 break;
@@ -1819,6 +1850,10 @@ static HRESULT ParseTheme(
1819 hr = ParseFonts(pThemeElement, pTheme); 1850 hr = ParseFonts(pThemeElement, pTheme);
1820 ThmExitOnFailure(hr, "Failed to parse theme fonts."); 1851 ThmExitOnFailure(hr, "Failed to parse theme fonts.");
1821 1852
1853 // Parse the images.
1854 hr = ParseImages(hModule, wzRelativePath, pThemeElement, pTheme);
1855 ThmExitOnFailure(hr, "Failed to parse theme images.");
1856
1822 // Parse the window element. 1857 // Parse the window element.
1823 hr = ParseWindow(hModule, wzRelativePath, pThemeElement, pTheme); 1858 hr = ParseWindow(hModule, wzRelativePath, pThemeElement, pTheme);
1824 ThmExitOnFailure(hr, "Failed to parse theme window element."); 1859 ThmExitOnFailure(hr, "Failed to parse theme window element.");
@@ -1950,16 +1985,37 @@ static HRESULT ParseOwnerDrawImage(
1950 ) 1985 )
1951{ 1986{
1952 HRESULT hr = S_OK; 1987 HRESULT hr = S_OK;
1988 DWORD dwValue = 0;
1953 BOOL fXmlFound = FALSE; 1989 BOOL fXmlFound = FALSE;
1954 BOOL fFoundImage = FALSE; 1990 BOOL fFoundImage = FALSE;
1955 Gdiplus::Bitmap* pBitmap = NULL; 1991 Gdiplus::Bitmap* pBitmap = NULL;
1956 1992
1993 hr = GetAttributeImageId(pTheme, pElement, L"ImageId", &dwValue);
1994 ThmExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to parse ImageId attribute.");
1995
1996 if (fXmlFound)
1997 {
1998 pImageRef->type = THEME_IMAGE_REFERENCE_TYPE_COMPLETE;
1999 pImageRef->dwImageIndex = dwValue;
2000 pImageRef->dwImageInstanceIndex = 0;
2001 fFoundImage = TRUE;
2002 }
2003 else
2004 {
2005 pImageRef->dwImageIndex = THEME_INVALID_ID;
2006 }
2007
1957 // Parse the optional background resource image. 2008 // Parse the optional background resource image.
1958 hr = GetAttributeImageFileOrResource(hModule, wzRelativePath, pElement, &pBitmap); 2009 hr = GetAttributeImageFileOrResource(hModule, wzRelativePath, pElement, &pBitmap);
1959 ThmExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed while parsing control image."); 2010 ThmExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed while parsing control image.");
1960 2011
1961 if (fXmlFound) 2012 if (fXmlFound)
1962 { 2013 {
2014 if (fFoundImage)
2015 {
2016 ThmExitWithRootFailure(hr, E_INVALIDDATA, "Unexpected image attribute with ImageId attribute.");
2017 }
2018
1963 hr = AddStandaloneImage(pTheme, &pBitmap, &pImageRef->dwImageInstanceIndex); 2019 hr = AddStandaloneImage(pTheme, &pBitmap, &pImageRef->dwImageInstanceIndex);
1964 ThmExitOnFailure(hr, "Failed to store owner draw image."); 2020 ThmExitOnFailure(hr, "Failed to store owner draw image.");
1965 2021
@@ -2284,6 +2340,41 @@ LExit:
2284 return hr; 2340 return hr;
2285} 2341}
2286 2342
2343static HRESULT GetAttributeImageId(
2344 __in THEME* pTheme,
2345 __in IXMLDOMNode* pixn,
2346 __in LPCWSTR wzAttribute,
2347 __inout DWORD* pdwValue
2348 )
2349{
2350 HRESULT hr = S_OK;
2351 BSTR bstrId = NULL;
2352 THEME_IMAGE* pImage = NULL;
2353 BOOL fXmlFound = FALSE;
2354
2355 hr = XmlGetAttribute(pixn, wzAttribute, &bstrId);
2356 ThmExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to get image id attribute.");
2357
2358 if (!fXmlFound)
2359 {
2360 ExitFunction1(hr = E_NOTFOUND);
2361 }
2362
2363 hr = DictGetValue(pTheme->sdhImageDictionary, bstrId, reinterpret_cast<void**>(&pImage));
2364 if (E_NOTFOUND == hr)
2365 {
2366 ThmExitWithRootFailure(hr, E_INVALIDDATA, "Unknown image id: %ls", bstrId);
2367 }
2368 ThmExitOnFailure(hr, "Failed to find image with id: %ls", bstrId);
2369
2370 *pdwValue = pImage->dwIndex;
2371
2372LExit:
2373 ReleaseBSTR(bstrId);
2374
2375 return hr;
2376}
2377
2287static HRESULT ParseSourceXY( 2378static HRESULT ParseSourceXY(
2288 __in IXMLDOMNode* pixn, 2379 __in IXMLDOMNode* pixn,
2289 __in THEME* pTheme, 2380 __in THEME* pTheme,
@@ -2366,6 +2457,7 @@ static HRESULT ParseSourceXY(
2366 } 2457 }
2367 2458
2368 pReference->type = THEME_IMAGE_REFERENCE_TYPE_PARTIAL; 2459 pReference->type = THEME_IMAGE_REFERENCE_TYPE_PARTIAL;
2460 pReference->dwImageIndex = THEME_INVALID_ID;
2369 pReference->dwImageInstanceIndex = dwImageInstanceIndex; 2461 pReference->dwImageInstanceIndex = dwImageInstanceIndex;
2370 pReference->nX = nX; 2462 pReference->nX = nX;
2371 pReference->nY = nY; 2463 pReference->nY = nY;
@@ -2747,6 +2839,131 @@ LExit:
2747 return hr; 2839 return hr;
2748} 2840}
2749 2841
2842
2843static HRESULT ParseImages(
2844 __in_opt HMODULE hModule,
2845 __in_opt LPCWSTR wzRelativePath,
2846 __in IXMLDOMElement* pElement,
2847 __in THEME* pTheme
2848 )
2849{
2850 HRESULT hr = S_OK;
2851 IXMLDOMNodeList* pixnl = NULL;
2852 IXMLDOMNode* pixn = NULL;
2853 LPWSTR sczImageId = NULL;
2854 DWORD dwImageIndex = 0;
2855 Gdiplus::Bitmap* pDefaultBitmap = NULL;
2856 IXMLDOMNodeList* pixnlAlternates = NULL;
2857 IXMLDOMNode* pixnAlternate = NULL;
2858 DWORD dwInstances = 0;
2859 THEME_IMAGE_INSTANCE* pInstance = NULL;
2860 BOOL fXmlFound = FALSE;
2861
2862 hr = XmlSelectNodes(pElement, L"Image", &pixnl);
2863 ThmExitOnFailure(hr, "Failed to find font elements.");
2864
2865 hr = pixnl->get_length(reinterpret_cast<long*>(&pTheme->cImages));
2866 ThmExitOnFailure(hr, "Failed to count the number of theme images.");
2867
2868 if (!pTheme->cImages)
2869 {
2870 ExitFunction1(hr = S_OK);
2871 }
2872
2873 pTheme->rgImages = static_cast<THEME_IMAGE*>(MemAlloc(sizeof(THEME_IMAGE) * pTheme->cImages, TRUE));
2874 ThmExitOnNull(pTheme->rgImages, hr, E_OUTOFMEMORY, "Failed to allocate theme images.");
2875
2876 hr = DictCreateWithEmbeddedKey(&pTheme->sdhImageDictionary, pTheme->cImages, reinterpret_cast<void**>(&pTheme->rgImages), offsetof(THEME_IMAGE, sczId), DICT_FLAG_NONE);
2877 ThmExitOnFailure(hr, "Failed to create image dictionary.");
2878
2879 while (S_OK == (hr = XmlNextElement(pixnl, &pixn, NULL)))
2880 {
2881 hr = XmlGetAttributeEx(pixn, L"Id", &sczImageId);
2882 ThmExitOnRequiredXmlQueryFailure(hr, "Failed to find image id.");
2883
2884 hr = DictKeyExists(pTheme->sdhImageDictionary, sczImageId);
2885 if (E_NOTFOUND != hr)
2886 {
2887 ThmExitOnFailure(hr, "Failed to check for duplicate image id.");
2888 ThmExitOnRootFailure(hr = E_INVALIDDATA, "Theme image id duplicated: %ls", sczImageId);
2889 }
2890
2891 THEME_IMAGE* pImage = pTheme->rgImages + dwImageIndex;
2892 pImage->sczId = sczImageId;
2893 sczImageId = NULL;
2894 pImage->dwIndex = dwImageIndex;
2895 ++dwImageIndex;
2896
2897 hr = GetAttributeImageFileOrResource(hModule, wzRelativePath, pixn, &pDefaultBitmap);
2898 ThmExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to parse Image: %ls", pImage->sczId);
2899
2900 if (!fXmlFound)
2901 {
2902 ThmExitWithRootFailure(hr, E_INVALIDDATA, "Image didn't specify an image: %ls.", pImage->sczId);
2903 }
2904
2905 hr = DictAddValue(pTheme->sdhImageDictionary, pImage);
2906 ThmExitOnFailure(hr, "Failed to add image to dictionary.");
2907
2908 // Parse alternates, if any.
2909 hr = XmlSelectNodes(pixn, L"AlternateResolution", &pixnlAlternates);
2910 ThmExitOnFailure(hr, "Failed to select child AlternateResolution nodes.");
2911
2912 hr = pixnlAlternates->get_length(reinterpret_cast<long*>(&dwInstances));
2913 ThmExitOnFailure(hr, "Failed to count the number of alternates.");
2914
2915 dwInstances += 1;
2916
2917 pImage->rgImageInstances = static_cast<THEME_IMAGE_INSTANCE*>(MemAlloc(sizeof(THEME_IMAGE_INSTANCE) * dwInstances, TRUE));
2918 ThmExitOnNull(pImage->rgImageInstances, hr, E_OUTOFMEMORY, "Failed to allocate image instances.");
2919
2920 pInstance = pImage->rgImageInstances;
2921 pInstance->pBitmap = pDefaultBitmap;
2922 pDefaultBitmap = NULL;
2923 pImage->cImageInstances += 1;
2924
2925 while (S_OK == (hr = XmlNextElement(pixnlAlternates, &pixnAlternate, NULL)))
2926 {
2927 pInstance = pImage->rgImageInstances + pImage->cImageInstances;
2928
2929 hr = GetAttributeImageFileOrResource(hModule, wzRelativePath, pixnAlternate, &pInstance->pBitmap);
2930 ThmExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to parse Image: '%ls', alternate resolution: %u", pImage->sczId, pImage->cImageInstances);
2931
2932 if (!fXmlFound)
2933 {
2934 ThmExitWithRootFailure(hr, E_INVALIDDATA, "Image: '%ls', alternate resolution: %u, didn't specify an image.", pImage->sczId, pImage->cImageInstances);
2935 }
2936
2937 ReleaseNullObject(pixnAlternate);
2938
2939 pImage->cImageInstances += 1;
2940 }
2941
2942 ReleaseNullObject(pixnlAlternates);
2943 ReleaseNullObject(pixn);
2944 }
2945 ThmExitOnFailure(hr, "Failed to enumerate all images.");
2946
2947 if (S_FALSE == hr)
2948 {
2949 hr = S_OK;
2950 }
2951
2952LExit:
2953 if (pDefaultBitmap)
2954 {
2955 delete pDefaultBitmap;
2956 }
2957
2958 ReleaseObject(pixnAlternate);
2959 ReleaseObject(pixnlAlternates);
2960 ReleaseStr(sczImageId);
2961 ReleaseObject(pixn);
2962 ReleaseObject(pixnl);
2963
2964 return hr;
2965}
2966
2750static HRESULT ParsePages( 2967static HRESULT ParsePages(
2751 __in_opt HMODULE hModule, 2968 __in_opt HMODULE hModule,
2752 __in_opt LPCWSTR wzRelativePath, 2969 __in_opt LPCWSTR wzRelativePath,
@@ -2853,8 +3070,8 @@ static HRESULT ParseImageLists(
2853 hr = XmlGetAttributeEx(pixnImageList, L"Name", &pThemeImageList->sczName); 3070 hr = XmlGetAttributeEx(pixnImageList, L"Name", &pThemeImageList->sczName);
2854 ThmExitOnRequiredXmlQueryFailure(hr, "Failed to find ImageList/@Name attribute."); 3071 ThmExitOnRequiredXmlQueryFailure(hr, "Failed to find ImageList/@Name attribute.");
2855 3072
2856 hr = XmlSelectNodes(pixnImageList, L"Image", &pixnlImages); 3073 hr = XmlSelectNodes(pixnImageList, L"ImageListItem", &pixnlImages);
2857 ThmExitOnFailure(hr, "Failed to select child Image nodes."); 3074 ThmExitOnFailure(hr, "Failed to select child ImageListItem nodes.");
2858 3075
2859 hr = pixnlImages->get_length(reinterpret_cast<long*>(&dwImageCount)); 3076 hr = pixnlImages->get_length(reinterpret_cast<long*>(&dwImageCount));
2860 ThmExitOnFailure(hr, "Failed to count the number of images in list."); 3077 ThmExitOnFailure(hr, "Failed to count the number of images in list.");
@@ -4300,7 +4517,24 @@ static void GetImageInstance(
4300 __out const THEME_IMAGE_INSTANCE** ppInstance 4517 __out const THEME_IMAGE_INSTANCE** ppInstance
4301 ) 4518 )
4302{ 4519{
4303 *ppInstance = pTheme->rgStandaloneImages + pReference->dwImageInstanceIndex; 4520 switch (pReference->type)
4521 {
4522 case THEME_IMAGE_REFERENCE_TYPE_PARTIAL:
4523 case THEME_IMAGE_REFERENCE_TYPE_COMPLETE:
4524 if (THEME_INVALID_ID == pReference->dwImageIndex)
4525 {
4526 *ppInstance = pTheme->rgStandaloneImages + pReference->dwImageInstanceIndex;
4527 }
4528 else
4529 {
4530 THEME_IMAGE* pImage = pTheme->rgImages + pReference->dwImageIndex;
4531 *ppInstance = pImage->rgImageInstances + pReference->dwImageInstanceIndex;
4532 }
4533 break;
4534 default:
4535 *ppInstance = NULL;
4536 break;
4537 }
4304} 4538}
4305 4539
4306static HRESULT DrawImageReference( 4540static HRESULT DrawImageReference(
@@ -4321,24 +4555,24 @@ static HRESULT DrawImageReference(
4321 int nHeight = 0; 4555 int nHeight = 0;
4322 4556
4323 GetImageInstance(pTheme, pReference, &pImageInstance); 4557 GetImageInstance(pTheme, pReference, &pImageInstance);
4324 if (THEME_IMAGE_REFERENCE_TYPE_PARTIAL == pReference->type) 4558 ExitOnNull(pImageInstance, hr, E_INVALIDARG, "Invalid image reference for drawing.");
4559
4560 switch (pReference->type)
4325 { 4561 {
4562 case THEME_IMAGE_REFERENCE_TYPE_PARTIAL:
4326 nX = pReference->nX; 4563 nX = pReference->nX;
4327 nY = pReference->nY; 4564 nY = pReference->nY;
4328 nWidth = pReference->nWidth; 4565 nWidth = pReference->nWidth;
4329 nHeight = pReference->nHeight; 4566 nHeight = pReference->nHeight;
4330 } 4567 break;
4331 else if (THEME_IMAGE_REFERENCE_TYPE_COMPLETE == pReference->type) 4568 case THEME_IMAGE_REFERENCE_TYPE_COMPLETE:
4332 {
4333 nX = 0; 4569 nX = 0;
4334 nY = 0; 4570 nY = 0;
4335 nWidth = pImageInstance->pBitmap->GetWidth(); 4571 nWidth = pImageInstance->pBitmap->GetWidth();
4336 nHeight = pImageInstance->pBitmap->GetHeight(); 4572 nHeight = pImageInstance->pBitmap->GetHeight();
4337 } 4573 break;
4338 else 4574 default:
4339 { 4575 ExitFunction1(hr = E_INVALIDARG); // This should be unreachable because GetImageInstance should have returned null.
4340 AssertSz(FALSE, "Invalid image reference type for drawing");
4341 ExitFunction1(hr = E_INVALIDARG);
4342 } 4576 }
4343 4577
4344 hr = DrawGdipBitmap(hdc, destX, destY, destWidth, destHeight, pImageInstance->pBitmap, nX, nY, nWidth, nHeight); 4578 hr = DrawGdipBitmap(hdc, destX, destY, destWidth, destHeight, pImageInstance->pBitmap, nX, nY, nWidth, nHeight);
@@ -4424,23 +4658,22 @@ static HRESULT DrawProgressBar(
4424 } 4658 }
4425 4659
4426 GetImageInstance(pTheme, pImageRef, &pInstance); 4660 GetImageInstance(pTheme, pImageRef, &pInstance);
4661 ExitOnNull(pInstance, hr, E_INVALIDARG, "Invalid image reference for drawing.");
4427 4662
4428 if (THEME_IMAGE_REFERENCE_TYPE_PARTIAL == pImageRef->type) 4663 switch (pImageRef->type)
4429 { 4664 {
4665 case THEME_IMAGE_REFERENCE_TYPE_PARTIAL:
4430 nSourceHeight = pImageRef->nHeight; 4666 nSourceHeight = pImageRef->nHeight;
4431 nSourceX = pImageRef->nX; 4667 nSourceX = pImageRef->nX;
4432 nSourceY = pImageRef->nY; 4668 nSourceY = pImageRef->nY;
4433 } 4669 break;
4434 else if (THEME_IMAGE_REFERENCE_TYPE_COMPLETE == pImageRef->type) 4670 case THEME_IMAGE_REFERENCE_TYPE_COMPLETE:
4435 {
4436 nSourceHeight = pInstance->pBitmap->GetHeight(); 4671 nSourceHeight = pInstance->pBitmap->GetHeight();
4437 nSourceX = 0; 4672 nSourceX = 0;
4438 nSourceY = 0; 4673 nSourceY = 0;
4439 } 4674 break;
4440 else 4675 default:
4441 { 4676 ExitFunction1(hr = E_INVALIDARG); // This should be unreachable because GetImageInstance should have returned null.
4442 AssertSz(FALSE, "Invalid image reference type for drawing");
4443 ExitFunction1(hr = E_INVALIDARG);
4444 } 4677 }
4445 4678
4446 // Draw the left side of the progress bar. 4679 // Draw the left side of the progress bar.
@@ -4721,6 +4954,21 @@ static void FreeFont(
4721} 4954}
4722 4955
4723 4956
4957static void FreeImage(
4958 __in THEME_IMAGE* pImage
4959 )
4960{
4961 if (pImage)
4962 {
4963 for (DWORD i = 0; i < pImage->cImageInstances; ++i)
4964 {
4965 FreeImageInstance(pImage->rgImageInstances + i);
4966 }
4967
4968 ReleaseStr(pImage->sczId);
4969 }
4970}
4971
4724static void FreeImageInstance( 4972static void FreeImageInstance(
4725 __in THEME_IMAGE_INSTANCE* pImageInstance 4973 __in THEME_IMAGE_INSTANCE* pImageInstance
4726 ) 4974 )
@@ -6232,6 +6480,7 @@ LExit:
6232} 6480}
6233 6481
6234static void ResizeControls( 6482static void ResizeControls(
6483 __in THEME* pTheme,
6235 __in DWORD cControls, 6484 __in DWORD cControls,
6236 __in THEME_CONTROL* rgControls, 6485 __in THEME_CONTROL* rgControls,
6237 __in const RECT* prcParent 6486 __in const RECT* prcParent
@@ -6240,11 +6489,12 @@ static void ResizeControls(
6240 for (DWORD i = 0; i < cControls; ++i) 6489 for (DWORD i = 0; i < cControls; ++i)
6241 { 6490 {
6242 THEME_CONTROL* pControl = rgControls + i; 6491 THEME_CONTROL* pControl = rgControls + i;
6243 ResizeControl(pControl, prcParent); 6492 ResizeControl(pTheme, pControl, prcParent);
6244 } 6493 }
6245} 6494}
6246 6495
6247static void ResizeControl( 6496static void ResizeControl(
6497 __in THEME* pTheme,
6248 __in THEME_CONTROL* pControl, 6498 __in THEME_CONTROL* pControl,
6249 __in const RECT* prcParent 6499 __in const RECT* prcParent
6250 ) 6500 )
@@ -6266,8 +6516,20 @@ static void ResizeControl(
6266 } 6516 }
6267#endif 6517#endif
6268 6518
6269 if (THEME_CONTROL_TYPE_LISTVIEW == pControl->type) 6519
6520 switch (pControl->type)
6270 { 6521 {
6522 case THEME_CONTROL_TYPE_BUTTON:
6523 for (DWORD i = 0; i < (sizeof(pControl->Button.rgImageRef) / sizeof(pControl->Button.rgImageRef[0])); ++i)
6524 {
6525 ScaleImageReference(pTheme, pControl->Button.rgImageRef + i, w, h);
6526 }
6527
6528 break;
6529 case THEME_CONTROL_TYPE_IMAGE:
6530 ScaleImageReference(pTheme, &pControl->Image.imageRef, w, h);
6531 break;
6532 case THEME_CONTROL_TYPE_LISTVIEW:
6271 SizeListViewColumns(pControl); 6533 SizeListViewColumns(pControl);
6272 6534
6273 for (DWORD j = 0; j < pControl->ListView.cColumns; ++j) 6535 for (DWORD j = 0; j < pControl->ListView.cColumns; ++j)
@@ -6278,12 +6540,21 @@ static void ResizeControl(
6278 return; 6540 return;
6279 } 6541 }
6280 } 6542 }
6543
6544 break;
6545 case THEME_CONTROL_TYPE_PROGRESSBAR:
6546 for (DWORD i = 0; i < pControl->ProgressBar.cImageRef; ++i)
6547 {
6548 ScaleImageReference(pTheme, pControl->ProgressBar.rgImageRef + i, 4, h);
6549 }
6550
6551 break;
6281 } 6552 }
6282 6553
6283 if (pControl->cControls) 6554 if (pControl->cControls)
6284 { 6555 {
6285 ::GetClientRect(pControl->hWnd, &rcControl); 6556 ::GetClientRect(pControl->hWnd, &rcControl);
6286 ResizeControls(pControl->cControls, pControl->rgControls, &rcControl); 6557 ResizeControls(pTheme, pControl->cControls, pControl->rgControls, &rcControl);
6287 } 6558 }
6288} 6559}
6289 6560
@@ -6390,6 +6661,67 @@ static void ScaleControl(
6390 } 6661 }
6391} 6662}
6392 6663
6664static void ScaleImageReference(
6665 __in THEME* pTheme,
6666 __in THEME_IMAGE_REFERENCE* pImageRef,
6667 __in int nDestWidth,
6668 __in int nDestHeight
6669 )
6670{
6671 THEME_IMAGE* pImage = NULL;
6672 THEME_IMAGE_INSTANCE* pDownscaleInstance = NULL;
6673 THEME_IMAGE_INSTANCE* pUpscaleInstance = NULL;
6674 THEME_IMAGE_INSTANCE* pInstance = NULL;
6675 DWORD dwIndex = THEME_INVALID_ID;
6676 DWORD64 qwPixels = 0;
6677 DWORD64 qwBestMatchPixels = 0;
6678
6679 if (THEME_IMAGE_REFERENCE_TYPE_COMPLETE == pImageRef->type && THEME_INVALID_ID != pImageRef->dwImageIndex)
6680 {
6681 pImage = pTheme->rgImages + pImageRef->dwImageIndex;
6682
6683 //The dimensions of the destination rectangle are compared to all of the available sources:
6684 // 1. If there is an exact match for width and height then that source will be used (no scaling required).
6685 // 2. If there is not an exact match then the smallest source whose width and height are larger or equal to the destination will be used and downscaled.
6686 // 3. If there is still no match then the largest source will be used and upscaled.
6687 for (DWORD i = 0; i < pImage->cImageInstances; ++i)
6688 {
6689 pInstance = pImage->rgImageInstances + i;
6690
6691 if (nDestWidth == (int)pInstance->pBitmap->GetWidth() && nDestHeight == (int)pInstance->pBitmap->GetHeight())
6692 {
6693 dwIndex = i;
6694 break;
6695 }
6696 else if (nDestWidth <= (int)pInstance->pBitmap->GetWidth() && nDestHeight <= (int)pInstance->pBitmap->GetHeight())
6697 {
6698 qwPixels = (DWORD64)pInstance->pBitmap->GetWidth() * pInstance->pBitmap->GetHeight();
6699 if (!pDownscaleInstance || qwPixels < qwBestMatchPixels)
6700 {
6701 qwBestMatchPixels = qwPixels;
6702 pDownscaleInstance = pInstance;
6703 dwIndex = i;
6704 }
6705 }
6706 else if (!pDownscaleInstance)
6707 {
6708 qwPixels = (DWORD64)pInstance->pBitmap->GetWidth() * pInstance->pBitmap->GetHeight();
6709 if (!pUpscaleInstance || qwPixels > qwBestMatchPixels)
6710 {
6711 qwBestMatchPixels = qwPixels;
6712 pUpscaleInstance = pInstance;
6713 dwIndex = i;
6714 }
6715 }
6716 }
6717
6718 if (THEME_INVALID_ID != dwIndex)
6719 {
6720 pImageRef->dwImageInstanceIndex = dwIndex;
6721 }
6722 }
6723}
6724
6393static void UnloadControls( 6725static void UnloadControls(
6394 __in DWORD cControls, 6726 __in DWORD cControls,
6395 __in THEME_CONTROL* rgControls 6727 __in THEME_CONTROL* rgControls