wine-staging/patches/shell32-IconCache/0001-shell32-iconcache-Generate-icons-from-available-icons-.patch

130 lines
4.8 KiB
Diff
Raw Normal View History

From e4e08d2ff648f1021d9833f7ea986c42dfc642ad Mon Sep 17 00:00:00 2001
2018-12-02 13:51:29 -08:00
From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= <gabrielopcode@gmail.com>
Date: Fri, 30 Nov 2018 12:20:40 +0200
Subject: [PATCH] shell32/iconcache: Generate icons from available icons if
some icon sizes failed to load
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
For icon sizes that fail to load, create them from another icon that
succeeded by resizing it, favoring icons that are the closest and larger
(to reduce pixelation artefacts) and with the closest aspect ratio as the
source of this operation (to be as generic as possible). For example, if
the icon that needs to be created must be 16x16, an 18x18 icon would get
picked over either a 32x32 (it's further from 16x16) or a 15x15 (icons
larger than 16x16 are favored since they're larger than the result, so
smaller icons are only picked if no other available icon is larger).
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45696
Signed-off-by: Gabriel Ivăncescu <gabrielopcode@gmail.com>
---
dlls/shell32/iconcache.c | 72 +++++++++++++++++++++++++++++++---------
1 file changed, 57 insertions(+), 15 deletions(-)
2018-12-02 13:51:29 -08:00
diff --git a/dlls/shell32/iconcache.c b/dlls/shell32/iconcache.c
index 1c61374a732..a1c91f4785e 100644
2018-12-02 13:51:29 -08:00
--- a/dlls/shell32/iconcache.c
+++ b/dlls/shell32/iconcache.c
@@ -21,6 +21,7 @@
#include <stdarg.h>
#include <string.h>
#include <sys/types.h>
+#include <math.h>
#define COBJMACROS
@@ -335,17 +336,6 @@ static INT SIC_IconAppend (const WCHAR *sourcefile, INT src_index, HICON *hicons
2018-12-02 13:51:29 -08:00
return ret;
}
-static BOOL get_imagelist_icon_size(int list, SIZE *size)
-{
- int cx, cy;
2018-12-02 13:51:29 -08:00
- if (list < 0 || list >= ARRAY_SIZE(shell_imagelists)) return FALSE;
-
- if (!ImageList_GetIconSize( shell_imagelists[list], &cx, &cy )) return FALSE;
- size->cx = cx;
- size->cy = cy;
- return TRUE;
2018-12-02 13:51:29 -08:00
-}
-
/****************************************************************************
* SIC_LoadIcon [internal]
*
@@ -356,15 +346,67 @@ static INT SIC_LoadIcon (const WCHAR *sourcefile, INT index, DWORD flags)
2018-12-02 13:51:29 -08:00
{
HICON hicons[ARRAY_SIZE(shell_imagelists)] = { 0 };
HICON hshortcuts[ARRAY_SIZE(hicons)] = { 0 };
+ SIZE size[ARRAY_SIZE(shell_imagelists)];
unsigned int i;
- SIZE size;
INT ret = -1;
+ /* Keep track of the sizes in case any icon fails to get extracted */
for (i = 0; i < ARRAY_SIZE(hicons); i++)
{
- if (!get_imagelist_icon_size( i, &size ) ||
- !PrivateExtractIconsW( sourcefile, index, size.cx, size.cy, &hicons[i], 0, 1, 0 ))
- WARN("Failed to load icon %d from %s.\n", index, debugstr_w(sourcefile));
2018-12-02 13:51:29 -08:00
+ ImageList_GetIconSize(shell_imagelists[i], &size[i].cx, &size[i].cy);
+ PrivateExtractIconsW(sourcefile, index, size[i].cx, size[i].cy, &hicons[i], 0, 1, 0);
+ }
+
+ /* Fill any icon handles that failed to get extracted, by resizing
+ another icon handle that succeeded and creating the icon from it.
+ Use a dumb O(n^2) algorithm since ARRAY_SIZE(hicons) is small */
+ for (i = 0; i < ARRAY_SIZE(hicons); i++)
+ {
2018-12-02 13:51:29 -08:00
+ unsigned int k, ix, iy;
+ BOOL failed = TRUE;
+ if (hicons[i]) continue;
+
+ for (k = 0; k < ARRAY_SIZE(hicons); k++)
+ {
+ if (hicons[k])
+ {
+ ix = iy = k;
+ failed = FALSE;
+ break;
+ }
+ }
+ if (failed) goto fail;
+
+ for (k++; k < ARRAY_SIZE(hicons); k++)
+ {
+ if (!hicons[k]) continue;
+
+ /* Find closest-sized icon, but favor larger icons to resize from */
+ if (size[k].cx >= size[i].cx)
+ ix = (size[ix].cx < size[i].cx || size[ix].cx > size[k].cx) ? k : ix;
+ else
+ ix = (size[ix].cx < size[i].cx && size[ix].cx < size[k].cx) ? k : ix;
+
+ if (size[k].cy >= size[i].cy)
+ iy = (size[iy].cy < size[i].cy || size[iy].cy > size[k].cy) ? k : iy;
+ else
+ iy = (size[iy].cy < size[i].cy && size[iy].cy < size[k].cy) ? k : iy;
+ }
+
+ /* Use the closest icon in aspect ratio if ix and iy differ */
+ if (ix != iy)
+ {
+ float i_ratio, ix_ratio, iy_ratio;
+ i_ratio = (float)size[i].cx / (float)size[i].cy;
+ ix_ratio = (float)size[ix].cx / (float)size[ix].cy;
+ iy_ratio = (float)size[iy].cx / (float)size[iy].cy;
+ if (fabsf(ix_ratio - i_ratio) > fabsf(iy_ratio - i_ratio))
+ ix = iy;
+ }
+
+ /* If this fails, we have to abort to prevent the image lists from
+ becoming out of sync and completely screwing the icons up */
+ hicons[i] = CopyImage(hicons[ix], IMAGE_ICON, size[i].cx, size[i].cy, 0);
if (!hicons[i]) goto fail;
}
--
2.34.1
2018-12-02 13:51:29 -08:00