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

133 lines
4.8 KiB
Diff
Raw Permalink Normal View History

From 3814dcc3cbbb1ffde8a208cf6612f8230703401a 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 | 75 ++++++++++++++++++++++++++++++++--------
1 file changed, 60 insertions(+), 15 deletions(-)
2018-12-02 13:51:29 -08:00
diff --git a/dlls/shell32/iconcache.c b/dlls/shell32/iconcache.c
index e3ae2499fe9..f60787406c4 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
@@ -333,17 +334,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]
*
@@ -354,15 +344,70 @@ 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;
+ INT x, y;
2018-12-02 13:51:29 -08:00
+ /* 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));
+ ImageList_GetIconSize(shell_imagelists[i], &x, &y);
+ size[i].cx = x;
+ size[i].cy = y;
2018-12-02 13:51:29 -08:00
+ 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.43.0
2018-12-02 13:51:29 -08:00