diff options
| author | Sean Hall <r.sean.hall@gmail.com> | 2021-06-04 13:37:30 -0500 |
|---|---|---|
| committer | Sean Hall <r.sean.hall@gmail.com> | 2021-06-04 14:57:11 -0500 |
| commit | 700b48c723531bfc38bab185f237d932144f3b26 (patch) | |
| tree | 0a7acc65b0de9f47e6b2d2fa3a2994809cfcbfa6 /src | |
| parent | 34639850c2c07a35c1e502e174866cd8630eb8ec (diff) | |
| download | wix-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 '')
| -rw-r--r-- | src/libs/dutil/WixToolset.DUtil/inc/thmutil.h | 14 | ||||
| -rw-r--r-- | src/libs/dutil/WixToolset.DUtil/thmutil.cpp | 382 |
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 | |||
| 110 | struct THEME_IMAGE_REFERENCE | 110 | struct 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 | ||
| 126 | struct THEME_IMAGE | ||
| 127 | { | ||
| 128 | LPWSTR sczId; | ||
| 129 | DWORD dwIndex; | ||
| 130 | |||
| 131 | DWORD cImageInstances; | ||
| 132 | THEME_IMAGE_INSTANCE* rgImageInstances; | ||
| 133 | }; | ||
| 134 | |||
| 125 | 135 | ||
| 126 | struct THEME_TAB | 136 | struct 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 | ); |
| 142 | static HRESULT GetAttributeImageId( | ||
| 143 | __in THEME* pTheme, | ||
| 144 | __in IXMLDOMNode* pixn, | ||
| 145 | __in LPCWSTR wzAttribute, | ||
| 146 | __inout DWORD* pdwValue | ||
| 147 | ); | ||
| 142 | static HRESULT ParseSourceXY( | 148 | static 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 | ); |
| 171 | static HRESULT ParseImages( | ||
| 172 | __in_opt HMODULE hModule, | ||
| 173 | __in_opt LPCWSTR wzRelativePath, | ||
| 174 | __in IXMLDOMElement* pElement, | ||
| 175 | __in THEME* pTheme | ||
| 176 | ); | ||
| 165 | static HRESULT ParsePages( | 177 | static 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( | |||
| 371 | static void FreeFont( | 383 | static void FreeFont( |
| 372 | __in THEME_FONT* pFont | 384 | __in THEME_FONT* pFont |
| 373 | ); | 385 | ); |
| 386 | static void FreeImage( | ||
| 387 | __in THEME_IMAGE* pImage | ||
| 388 | ); | ||
| 374 | static void FreeImageInstance( | 389 | static 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 | ); |
| 488 | static void ResizeControls( | 503 | static 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 | ); |
| 493 | static void ResizeControl( | 509 | static 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 | ); |
| 552 | static void ScaleImageReference( | ||
| 553 | __in THEME* pTheme, | ||
| 554 | __in THEME_IMAGE_REFERENCE* pImageRef, | ||
| 555 | __in int nDestWidth, | ||
| 556 | __in int nDestHeight | ||
| 557 | ); | ||
| 535 | static void UnloadControls( | 558 | static 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 | ||
| 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 | |||
| 2287 | static HRESULT ParseSourceXY( | 2378 | static 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 | |||
| 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 | |||
| 2750 | static HRESULT ParsePages( | 2967 | static 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 | ||
| 4306 | static HRESULT DrawImageReference( | 4540 | static 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 | ||
| 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 | |||
| 4724 | static void FreeImageInstance( | 4972 | static 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 | ||
| 6234 | static void ResizeControls( | 6482 | static 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 | ||
| 6247 | static void ResizeControl( | 6496 | static 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 | ||
| 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 | |||
| 6393 | static void UnloadControls( | 6725 | static void UnloadControls( |
| 6394 | __in DWORD cControls, | 6726 | __in DWORD cControls, |
| 6395 | __in THEME_CONTROL* rgControls | 6727 | __in THEME_CONTROL* rgControls |
