@joebigelow / wix / commits / 700b48c7

Add thmutil Image element to allow specifying multiple resolutions. Rename previous Image element to ImageListItem.

Add thmutil Image element to allow specifying multiple resolutions. Rename previous Image element to ImageListItem. Last partial fix for #6155

Sean Hall committed Jun 4, 2021 at 13:37 UTC 700b48c723531bfc38bab185f237d932144f3b26
2 files changed +371 -25
src/libs/dutil/WixToolset.DUtil/inc/thmutil.h
+14
@@ -110,6 +110,7 @@ struct THEME_COLUMN
110 struct THEME_IMAGE_REFERENCE
111 {
112 THEME_IMAGE_REFERENCE_TYPE type;
113 + DWORD dwImageIndex;
114 DWORD dwImageInstanceIndex;
115 int nX;
116 int nY;
@@ -122,6 +123,15 @@ struct THEME_IMAGE_INSTANCE
123 Gdiplus::Bitmap* pBitmap;
124 };
125
126 +struct THEME_IMAGE
127 +{
128 + LPWSTR sczId;
129 + DWORD dwIndex;
130 +
131 + DWORD cImageInstances;
132 + THEME_IMAGE_INSTANCE* rgImageInstances;
133 +};
134 +
135
136 struct THEME_TAB
137 {
@@ -342,6 +352,9 @@ struct THEME
352 DWORD cFonts;
353 THEME_FONT* rgFonts;
354
355 + DWORD cImages;
356 + THEME_IMAGE* rgImages;
357 +
358 DWORD cStandaloneImages;
359 THEME_IMAGE_INSTANCE* rgStandaloneImages;
360
@@ -356,6 +369,7 @@ struct THEME
369
370 // internal state variables -- do not use outside ThmUtil.cpp
371 STRINGDICT_HANDLE sdhFontDictionary;
372 + STRINGDICT_HANDLE sdhImageDictionary;
373 HWND hwndParent; // parent for loaded controls
374 HWND hwndHover; // current hwnd hovered over
375 DWORD dwCurrentPageId;
src/libs/dutil/WixToolset.DUtil/thmutil.cpp
+357 -25
@@ -139,6 +139,12 @@ static HRESULT GetAttributeFontId(
139 __in LPCWSTR wzAttribute,
140 __inout DWORD* pdwValue
141 );
142 +static HRESULT GetAttributeImageId(
143 + __in THEME* pTheme,
144 + __in IXMLDOMNode* pixn,
145 + __in LPCWSTR wzAttribute,
146 + __inout DWORD* pdwValue
147 + );
148 static HRESULT ParseSourceXY(
149 __in IXMLDOMNode* pixn,
150 __in THEME* pTheme,
@@ -162,6 +168,12 @@ static HRESULT ParseFonts(
168 __in IXMLDOMElement* pElement,
169 __in THEME* pTheme
170 );
171 +static HRESULT ParseImages(
172 + __in_opt HMODULE hModule,
173 + __in_opt LPCWSTR wzRelativePath,
174 + __in IXMLDOMElement* pElement,
175 + __in THEME* pTheme
176 + );
177 static HRESULT ParsePages(
178 __in_opt HMODULE hModule,
179 __in_opt LPCWSTR wzRelativePath,
@@ -371,6 +383,9 @@ static void FreeFontInstance(
383 static void FreeFont(
384 __in THEME_FONT* pFont
385 );
386 +static void FreeImage(
387 + __in THEME_IMAGE* pImage
388 + );
389 static void FreeImageInstance(
390 __in THEME_IMAGE_INSTANCE* pImageInstance
391 );
@@ -486,11 +501,13 @@ static HRESULT LoadControlString(
501 __in HMODULE hResModule
502 );
503 static void ResizeControls(
504 + __in THEME* pTheme,
505 __in DWORD cControls,
506 __in THEME_CONTROL* rgControls,
507 __in const RECT* prcParent
508 );
509 static void ResizeControl(
510 + __in THEME* pTheme,
511 __in THEME_CONTROL* pControl,
512 __in const RECT* prcParent
513 );
@@ -532,6 +549,12 @@ static void GetControls(
549 __out DWORD& cControls,
550 __out THEME_CONTROL*& rgControls
551 );
552 +static void ScaleImageReference(
553 + __in THEME* pTheme,
554 + __in THEME_IMAGE_REFERENCE* pImageRef,
555 + __in int nDestWidth,
556 + __in int nDestHeight
557 + );
558 static void UnloadControls(
559 __in DWORD cControls,
560 __in THEME_CONTROL* rgControls
@@ -685,6 +708,11 @@ DAPI_(void) ThemeFree(
708 FreeFont(pTheme->rgFonts + i);
709 }
710
711 + for (DWORD i = 0; i < pTheme->cImages; ++i)
712 + {
713 + FreeImage(pTheme->rgImages + i);
714 + }
715 +
716 for (DWORD i = 0; i < pTheme->cStandaloneImages; ++i)
717 {
718 FreeImageInstance(pTheme->rgStandaloneImages + i);
@@ -708,10 +736,12 @@ DAPI_(void) ThemeFree(
736 ReleaseMem(pTheme->rgControls);
737 ReleaseMem(pTheme->rgPages);
738 ReleaseMem(pTheme->rgStandaloneImages);
739 + ReleaseMem(pTheme->rgImages);
740 ReleaseMem(pTheme->rgFonts);
741
742 ReleaseStr(pTheme->sczCaption);
743 ReleaseDict(pTheme->sdhFontDictionary);
744 + ReleaseDict(pTheme->sdhImageDictionary);
745 ReleaseMem(pTheme);
746 }
747 }
@@ -1063,7 +1093,8 @@ extern "C" LRESULT CALLBACK ThemeDefWindowProc(
1093 {
1094 pTheme->fForceResize = FALSE;
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);
1098 return 0;
1099 }
1100 break;
@@ -1819,6 +1850,10 @@ static HRESULT ParseTheme(
1850 hr = ParseFonts(pThemeElement, pTheme);
1851 ThmExitOnFailure(hr, "Failed to parse theme fonts.");
1852
1853 + // Parse the images.
1854 + hr = ParseImages(hModule, wzRelativePath, pThemeElement, pTheme);
1855 + ThmExitOnFailure(hr, "Failed to parse theme images.");
1856 +
1857 // Parse the window element.
1858 hr = ParseWindow(hModule, wzRelativePath, pThemeElement, pTheme);
1859 ThmExitOnFailure(hr, "Failed to parse theme window element.");
@@ -1950,16 +1985,37 @@ static HRESULT ParseOwnerDrawImage(
1985 )
1986 {
1987 HRESULT hr = S_OK;
1988 + DWORD dwValue = 0;
1989 BOOL fXmlFound = FALSE;
1990 BOOL fFoundImage = FALSE;
1991 Gdiplus::Bitmap* pBitmap = NULL;
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 +
2008 // Parse the optional background resource image.
2009 hr = GetAttributeImageFileOrResource(hModule, wzRelativePath, pElement, &pBitmap);
2010 ThmExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed while parsing control image.");
2011
2012 if (fXmlFound)
2013 {
2014 + if (fFoundImage)
2015 + {
2016 + ThmExitWithRootFailure(hr, E_INVALIDDATA, "Unexpected image attribute with ImageId attribute.");
2017 + }
2018 +
2019 hr = AddStandaloneImage(pTheme, &pBitmap, &pImageRef->dwImageInstanceIndex);
2020 ThmExitOnFailure(hr, "Failed to store owner draw image.");
2021
@@ -2284,6 +2340,41 @@ LExit:
2340 return hr;
2341 }
2342
2343 +static 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 +
2372 +LExit:
2373 + ReleaseBSTR(bstrId);
2374 +
2375 + return hr;
2376 +}
2377 +
2378 static HRESULT ParseSourceXY(
2379 __in IXMLDOMNode* pixn,
2380 __in THEME* pTheme,
@@ -2366,6 +2457,7 @@ static HRESULT ParseSourceXY(
2457 }
2458
2459 pReference->type = THEME_IMAGE_REFERENCE_TYPE_PARTIAL;
2460 + pReference->dwImageIndex = THEME_INVALID_ID;
2461 pReference->dwImageInstanceIndex = dwImageInstanceIndex;
2462 pReference->nX = nX;
2463 pReference->nY = nY;
@@ -2747,6 +2839,131 @@ LExit:
2839 return hr;
2840 }
2841
2842 +
2843 +static 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 +
2952 +LExit:
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 +
2967 static HRESULT ParsePages(
2968 __in_opt HMODULE hModule,
2969 __in_opt LPCWSTR wzRelativePath,
@@ -2853,8 +3070,8 @@ static HRESULT ParseImageLists(
3070 hr = XmlGetAttributeEx(pixnImageList, L"Name", &pThemeImageList->sczName);
3071 ThmExitOnRequiredXmlQueryFailure(hr, "Failed to find ImageList/@Name attribute.");
3072
2856 - hr = XmlSelectNodes(pixnImageList, L"Image", &pixnlImages);
2857 - ThmExitOnFailure(hr, "Failed to select child Image nodes.");
3073 + hr = XmlSelectNodes(pixnImageList, L"ImageListItem", &pixnlImages);
3074 + ThmExitOnFailure(hr, "Failed to select child ImageListItem nodes.");
3075
3076 hr = pixnlImages->get_length(reinterpret_cast<long*>(&dwImageCount));
3077 ThmExitOnFailure(hr, "Failed to count the number of images in list.");
@@ -4300,7 +4517,24 @@ static void GetImageInstance(
4517 __out const THEME_IMAGE_INSTANCE** ppInstance
4518 )
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 + }
4538 }
4539
4540 static HRESULT DrawImageReference(
@@ -4321,24 +4555,24 @@ static HRESULT DrawImageReference(
4555 int nHeight = 0;
4556
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)
4561 {
4562 + case THEME_IMAGE_REFERENCE_TYPE_PARTIAL:
4563 nX = pReference->nX;
4564 nY = pReference->nY;
4565 nWidth = pReference->nWidth;
4566 nHeight = pReference->nHeight;
4330 - }
4331 - else if (THEME_IMAGE_REFERENCE_TYPE_COMPLETE == pReference->type)
4332 - {
4567 + break;
4568 + case THEME_IMAGE_REFERENCE_TYPE_COMPLETE:
4569 nX = 0;
4570 nY = 0;
4571 nWidth = pImageInstance->pBitmap->GetWidth();
4572 nHeight = pImageInstance->pBitmap->GetHeight();
4337 - }
4338 - else
4339 - {
4340 - AssertSz(FALSE, "Invalid image reference type for drawing");
4341 - ExitFunction1(hr = E_INVALIDARG);
4573 + break;
4574 + default:
4575 + ExitFunction1(hr = E_INVALIDARG); // This should be unreachable because GetImageInstance should have returned null.
4576 }
4577
4578 hr = DrawGdipBitmap(hdc, destX, destY, destWidth, destHeight, pImageInstance->pBitmap, nX, nY, nWidth, nHeight);
@@ -4424,23 +4658,22 @@ static HRESULT DrawProgressBar(
4658 }
4659
4660 GetImageInstance(pTheme, pImageRef, &pInstance);
4661 + ExitOnNull(pInstance, hr, E_INVALIDARG, "Invalid image reference for drawing.");
4662
4428 - if (THEME_IMAGE_REFERENCE_TYPE_PARTIAL == pImageRef->type)
4663 + switch (pImageRef->type)
4664 {
4665 + case THEME_IMAGE_REFERENCE_TYPE_PARTIAL:
4666 nSourceHeight = pImageRef->nHeight;
4667 nSourceX = pImageRef->nX;
4668 nSourceY = pImageRef->nY;
4433 - }
4434 - else if (THEME_IMAGE_REFERENCE_TYPE_COMPLETE == pImageRef->type)
4435 - {
4669 + break;
4670 + case THEME_IMAGE_REFERENCE_TYPE_COMPLETE:
4671 nSourceHeight = pInstance->pBitmap->GetHeight();
4672 nSourceX = 0;
4673 nSourceY = 0;
4439 - }
4440 - else
4441 - {
4442 - AssertSz(FALSE, "Invalid image reference type for drawing");
4443 - ExitFunction1(hr = E_INVALIDARG);
4674 + break;
4675 + default:
4676 + ExitFunction1(hr = E_INVALIDARG); // This should be unreachable because GetImageInstance should have returned null.
4677 }
4678
4679 // Draw the left side of the progress bar.
@@ -4721,6 +4954,21 @@ static void FreeFont(
4954 }
4955
4956
4957 +static 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 +
4972 static void FreeImageInstance(
4973 __in THEME_IMAGE_INSTANCE* pImageInstance
4974 )
@@ -6232,6 +6480,7 @@ LExit:
6480 }
6481
6482 static void ResizeControls(
6483 + __in THEME* pTheme,
6484 __in DWORD cControls,
6485 __in THEME_CONTROL* rgControls,
6486 __in const RECT* prcParent
@@ -6240,11 +6489,12 @@ static void ResizeControls(
6489 for (DWORD i = 0; i < cControls; ++i)
6490 {
6491 THEME_CONTROL* pControl = rgControls + i;
6243 - ResizeControl(pControl, prcParent);
6492 + ResizeControl(pTheme, pControl, prcParent);
6493 }
6494 }
6495
6496 static void ResizeControl(
6497 + __in THEME* pTheme,
6498 __in THEME_CONTROL* pControl,
6499 __in const RECT* prcParent
6500 )
@@ -6266,8 +6516,20 @@ static void ResizeControl(
6516 }
6517 #endif
6518
6269 - if (THEME_CONTROL_TYPE_LISTVIEW == pControl->type)
6519 +
6520 + switch (pControl->type)
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:
6533 SizeListViewColumns(pControl);
6534
6535 for (DWORD j = 0; j < pControl->ListView.cColumns; ++j)
@@ -6278,12 +6540,21 @@ static void ResizeControl(
6540 return;
6541 }
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;
6552 }
6553
6554 if (pControl->cControls)
6555 {
6556 ::GetClientRect(pControl->hWnd, &rcControl);
6286 - ResizeControls(pControl->cControls, pControl->rgControls, &rcControl);
6557 + ResizeControls(pTheme, pControl->cControls, pControl->rgControls, &rcControl);
6558 }
6559 }
6560
@@ -6390,6 +6661,67 @@ static void ScaleControl(
6661 }
6662 }
6663
6664 +static 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 +
6725 static void UnloadControls(
6726 __in DWORD cControls,
6727 __in THEME_CONTROL* rgControls