From 4ba27f79309b440b3a6d39807a79065b96679352 Mon Sep 17 00:00:00 2001
From: Dmitry Timoshkov <dmitry@baikal.ru>
Date: Mon, 14 Jan 2013 12:45:24 +0800
Subject: [PATCH] windowscodecs: Implement CreateBitmapFromHICON.

---
 dlls/windowscodecs/Makefile.in    |   2 +-
 dlls/windowscodecs/imgfactory.c   | 138 +++++++++++++++++++++++++++++-
 dlls/windowscodecs/tests/bitmap.c |   4 -
 3 files changed, 136 insertions(+), 8 deletions(-)

diff --git a/dlls/windowscodecs/Makefile.in b/dlls/windowscodecs/Makefile.in
index d031daa85a1..ffe092565d0 100644
--- a/dlls/windowscodecs/Makefile.in
+++ b/dlls/windowscodecs/Makefile.in
@@ -1,6 +1,6 @@
 MODULE    = windowscodecs.dll
 IMPORTLIB = windowscodecs
-IMPORTS   = uuid ole32 oleaut32 shlwapi advapi32 rpcrt4
+IMPORTS   = uuid ole32 oleaut32 rpcrt4 shlwapi user32 gdi32 advapi32
 EXTRAINCL = @PNGINCL@
 EXTRADEFS = -DENTRY_PREFIX=WIC_ -DPROXY_DELEGATION -DWINE_REGISTER_DLL
 EXTRALIBS = @APPLICATIONSERVICESLIB@
diff --git a/dlls/windowscodecs/imgfactory.c b/dlls/windowscodecs/imgfactory.c
index 1d05ef55348..8762c816694 100644
--- a/dlls/windowscodecs/imgfactory.c
+++ b/dlls/windowscodecs/imgfactory.c
@@ -597,10 +597,142 @@ static HRESULT WINAPI ComponentFactory_CreateBitmapFromHBITMAP(IWICComponentFact
 }
 
 static HRESULT WINAPI ComponentFactory_CreateBitmapFromHICON(IWICComponentFactory *iface,
-    HICON hIcon, IWICBitmap **ppIBitmap)
+    HICON hicon, IWICBitmap **bitmap)
 {
-    FIXME("(%p,%p,%p): stub\n", iface, hIcon, ppIBitmap);
-    return E_NOTIMPL;
+    IWICBitmapLock *lock;
+    ICONINFO info;
+    BITMAP bm;
+    int width, height, x, y;
+    UINT stride, size;
+    BYTE *buffer;
+    DWORD *bits;
+    BITMAPINFO bi;
+    HDC hdc;
+    BOOL has_alpha;
+    HRESULT hr;
+
+    TRACE("(%p,%p,%p)\n", iface, hicon, bitmap);
+
+    if (!bitmap) return E_INVALIDARG;
+
+    if (!GetIconInfo(hicon, &info))
+        return HRESULT_FROM_WIN32(GetLastError());
+
+    GetObjectW(info.hbmColor ? info.hbmColor : info.hbmMask, sizeof(bm), &bm);
+
+    width = bm.bmWidth;
+    height = info.hbmColor ? abs(bm.bmHeight) : abs(bm.bmHeight) / 2;
+    stride = width * 4;
+    size = stride * height;
+
+    hr = BitmapImpl_Create(width, height, stride, size, NULL,
+                           &GUID_WICPixelFormat32bppBGRA, WICBitmapCacheOnLoad, bitmap);
+    if (hr != S_OK) goto failed;
+
+    hr = IWICBitmap_Lock(*bitmap, NULL, WICBitmapLockWrite, &lock);
+    if (hr != S_OK)
+    {
+        IWICBitmap_Release(*bitmap);
+        goto failed;
+    }
+    IWICBitmapLock_GetDataPointer(lock, &size, &buffer);
+
+    hdc = CreateCompatibleDC(0);
+
+    memset(&bi, 0, sizeof(bi));
+    bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
+    bi.bmiHeader.biWidth = width;
+    bi.bmiHeader.biHeight = -height;
+    bi.bmiHeader.biPlanes = 1;
+    bi.bmiHeader.biBitCount = 32;
+    bi.bmiHeader.biCompression = BI_RGB;
+
+    has_alpha = FALSE;
+
+    if (info.hbmColor)
+    {
+        GetDIBits(hdc, info.hbmColor, 0, height, buffer, &bi, DIB_RGB_COLORS);
+
+        if (bm.bmBitsPixel == 32)
+        {
+            /* If any pixel has a non-zero alpha, ignore hbmMask */
+            bits = (DWORD *)buffer;
+            for (x = 0; x < width && !has_alpha; x++, bits++)
+            {
+                for (y = 0; y < height; y++)
+                {
+                    if (*bits & 0xff000000)
+                    {
+                        has_alpha = TRUE;
+                        break;
+                    }
+                }
+            }
+        }
+    }
+    else
+        GetDIBits(hdc, info.hbmMask, 0, height, buffer, &bi, DIB_RGB_COLORS);
+
+    if (!has_alpha)
+    {
+        DWORD *rgba;
+
+        if (info.hbmMask)
+        {
+            BYTE *mask;
+
+            mask = HeapAlloc(GetProcessHeap(), 0, size);
+            if (!mask)
+            {
+                IWICBitmapLock_Release(lock);
+                IWICBitmap_Release(*bitmap);
+                DeleteDC(hdc);
+                hr = E_OUTOFMEMORY;
+                goto failed;
+            }
+
+            /* read alpha data from the mask */
+            GetDIBits(hdc, info.hbmMask, info.hbmColor ? 0 : height, height, mask, &bi, DIB_RGB_COLORS);
+
+            for (y = 0; y < height; y++)
+            {
+                rgba = (DWORD *)(buffer + y * stride);
+                bits = (DWORD *)(mask + y * stride);
+
+                for (x = 0; x < width; x++, rgba++, bits++)
+                {
+                    if (!info.hbmColor) *rgba = ~*rgba;
+
+                    if (*bits)
+                        *rgba = 0;
+                    else
+                        *rgba |= 0xff000000;
+                }
+            }
+
+            HeapFree(GetProcessHeap(), 0, mask);
+        }
+        else
+        {
+            /* set constant alpha of 255 */
+            for (y = 0; y < height; y++)
+            {
+                rgba = (DWORD *)(buffer + y * stride);
+                for (x = 0; x < width; x++, rgba++)
+                    *rgba |= 0xff000000;
+            }
+        }
+
+    }
+
+    IWICBitmapLock_Release(lock);
+    DeleteDC(hdc);
+
+failed:
+    DeleteObject(info.hbmColor);
+    DeleteObject(info.hbmMask);
+
+    return hr;
 }
 
 static HRESULT WINAPI ComponentFactory_CreateComponentEnumerator(IWICComponentFactory *iface,
diff --git a/dlls/windowscodecs/tests/bitmap.c b/dlls/windowscodecs/tests/bitmap.c
index 40b8ce6865a..fb7183ba255 100644
--- a/dlls/windowscodecs/tests/bitmap.c
+++ b/dlls/windowscodecs/tests/bitmap.c
@@ -529,19 +529,15 @@ static void test_CreateBitmapFromHICON(void)
     DeleteObject(info.hbmMask);
 
     hr = IWICImagingFactory_CreateBitmapFromHICON(factory, 0, NULL);
-todo_wine
     ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got %#x\n", hr);
 
     hr = IWICImagingFactory_CreateBitmapFromHICON(factory, 0, &bitmap);
-todo_wine
     ok(hr == HRESULT_FROM_WIN32(ERROR_INVALID_CURSOR_HANDLE), "expected ERROR_INVALID_CURSOR_HANDLE, got %#x\n", hr);
 
     hr = IWICImagingFactory_CreateBitmapFromHICON(factory, icon, NULL);
-todo_wine
     ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got %#x\n", hr);
 
     hr = IWICImagingFactory_CreateBitmapFromHICON(factory, icon, &bitmap);
-todo_wine
     ok(hr == S_OK, "CreateBitmapFromHICON error %#x\n", hr);
     DestroyIcon(icon);
     if (hr != S_OK) return;
-- 
GitLab