| /* |
| * Copyright 2012 Vincent Povirk for CodeWeavers |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
| */ |
| |
| #include "config.h" |
| |
| #include <stdarg.h> |
| |
| #define COBJMACROS |
| |
| #include "windef.h" |
| #include "winbase.h" |
| #include "objbase.h" |
| |
| #include "wincodecs_private.h" |
| |
| #include "wine/debug.h" |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(wincodecs); |
| |
| /* WARNING: .NET Media Integration Layer (MIL) directly dereferences |
| * BitmapImpl members and depends on its exact layout. |
| */ |
| typedef struct BitmapImpl { |
| IMILUnknown1 IMILUnknown1_iface; |
| LONG ref; |
| IMILBitmapSource IMILBitmapSource_iface; |
| IWICBitmap IWICBitmap_iface; |
| IMILUnknown2 IMILUnknown2_iface; |
| IWICPalette *palette; |
| int palette_set; |
| LONG lock; /* 0 if not locked, -1 if locked for writing, count if locked for reading */ |
| BYTE *data; |
| UINT width, height; |
| UINT stride; |
| UINT bpp; |
| WICPixelFormatGUID pixelformat; |
| double dpix, dpiy; |
| CRITICAL_SECTION cs; |
| } BitmapImpl; |
| |
| typedef struct BitmapLockImpl { |
| IWICBitmapLock IWICBitmapLock_iface; |
| LONG ref; |
| BitmapImpl *parent; |
| UINT width, height; |
| BYTE *data; |
| } BitmapLockImpl; |
| |
| static inline BitmapImpl *impl_from_IWICBitmap(IWICBitmap *iface) |
| { |
| return CONTAINING_RECORD(iface, BitmapImpl, IWICBitmap_iface); |
| } |
| |
| static inline BitmapImpl *impl_from_IMILBitmapSource(IMILBitmapSource *iface) |
| { |
| return CONTAINING_RECORD(iface, BitmapImpl, IMILBitmapSource_iface); |
| } |
| |
| static inline BitmapImpl *impl_from_IMILUnknown1(IMILUnknown1 *iface) |
| { |
| return CONTAINING_RECORD(iface, BitmapImpl, IMILUnknown1_iface); |
| } |
| |
| static inline BitmapImpl *impl_from_IMILUnknown2(IMILUnknown2 *iface) |
| { |
| return CONTAINING_RECORD(iface, BitmapImpl, IMILUnknown2_iface); |
| } |
| |
| static inline BitmapLockImpl *impl_from_IWICBitmapLock(IWICBitmapLock *iface) |
| { |
| return CONTAINING_RECORD(iface, BitmapLockImpl, IWICBitmapLock_iface); |
| } |
| |
| static BOOL BitmapImpl_AcquireLock(BitmapImpl *This, int write) |
| { |
| if (write) |
| { |
| return 0 == InterlockedCompareExchange(&This->lock, -1, 0); |
| } |
| else |
| { |
| while (1) |
| { |
| LONG prev_val = This->lock; |
| if (prev_val == -1) |
| return FALSE; |
| if (prev_val == InterlockedCompareExchange(&This->lock, prev_val+1, prev_val)) |
| return TRUE; |
| } |
| } |
| } |
| |
| static void BitmapImpl_ReleaseLock(BitmapImpl *This) |
| { |
| while (1) |
| { |
| LONG prev_val = This->lock, new_val; |
| if (prev_val == -1) |
| new_val = 0; |
| else |
| new_val = prev_val - 1; |
| if (prev_val == InterlockedCompareExchange(&This->lock, new_val, prev_val)) |
| break; |
| } |
| } |
| |
| |
| static HRESULT WINAPI BitmapLockImpl_QueryInterface(IWICBitmapLock *iface, REFIID iid, |
| void **ppv) |
| { |
| BitmapLockImpl *This = impl_from_IWICBitmapLock(iface); |
| TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); |
| |
| if (!ppv) return E_INVALIDARG; |
| |
| if (IsEqualIID(&IID_IUnknown, iid) || |
| IsEqualIID(&IID_IWICBitmapLock, iid)) |
| { |
| *ppv = &This->IWICBitmapLock_iface; |
| } |
| else |
| { |
| *ppv = NULL; |
| return E_NOINTERFACE; |
| } |
| |
| IUnknown_AddRef((IUnknown*)*ppv); |
| return S_OK; |
| } |
| |
| static ULONG WINAPI BitmapLockImpl_AddRef(IWICBitmapLock *iface) |
| { |
| BitmapLockImpl *This = impl_from_IWICBitmapLock(iface); |
| ULONG ref = InterlockedIncrement(&This->ref); |
| |
| TRACE("(%p) refcount=%u\n", iface, ref); |
| |
| return ref; |
| } |
| |
| static ULONG WINAPI BitmapLockImpl_Release(IWICBitmapLock *iface) |
| { |
| BitmapLockImpl *This = impl_from_IWICBitmapLock(iface); |
| ULONG ref = InterlockedDecrement(&This->ref); |
| |
| TRACE("(%p) refcount=%u\n", iface, ref); |
| |
| if (ref == 0) |
| { |
| BitmapImpl_ReleaseLock(This->parent); |
| IWICBitmap_Release(&This->parent->IWICBitmap_iface); |
| HeapFree(GetProcessHeap(), 0, This); |
| } |
| |
| return ref; |
| } |
| |
| static HRESULT WINAPI BitmapLockImpl_GetSize(IWICBitmapLock *iface, |
| UINT *puiWidth, UINT *puiHeight) |
| { |
| BitmapLockImpl *This = impl_from_IWICBitmapLock(iface); |
| TRACE("(%p,%p,%p)\n", iface, puiWidth, puiHeight); |
| |
| if (!puiWidth || !puiHeight) |
| return E_INVALIDARG; |
| |
| *puiWidth = This->width; |
| *puiHeight = This->height; |
| |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI BitmapLockImpl_GetStride(IWICBitmapLock *iface, |
| UINT *pcbStride) |
| { |
| BitmapLockImpl *This = impl_from_IWICBitmapLock(iface); |
| TRACE("(%p,%p)\n", iface, pcbStride); |
| |
| if (!pcbStride) |
| return E_INVALIDARG; |
| |
| *pcbStride = This->parent->stride; |
| |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI BitmapLockImpl_GetDataPointer(IWICBitmapLock *iface, |
| UINT *pcbBufferSize, BYTE **ppbData) |
| { |
| BitmapLockImpl *This = impl_from_IWICBitmapLock(iface); |
| TRACE("(%p,%p,%p)\n", iface, pcbBufferSize, ppbData); |
| |
| if (!pcbBufferSize || !ppbData) |
| return E_INVALIDARG; |
| |
| *pcbBufferSize = This->parent->stride * (This->height - 1) + |
| ((This->parent->bpp * This->width) + 7)/8; |
| *ppbData = This->data; |
| |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI BitmapLockImpl_GetPixelFormat(IWICBitmapLock *iface, |
| WICPixelFormatGUID *pPixelFormat) |
| { |
| BitmapLockImpl *This = impl_from_IWICBitmapLock(iface); |
| TRACE("(%p,%p)\n", iface, pPixelFormat); |
| |
| return IWICBitmap_GetPixelFormat(&This->parent->IWICBitmap_iface, pPixelFormat); |
| } |
| |
| static const IWICBitmapLockVtbl BitmapLockImpl_Vtbl = { |
| BitmapLockImpl_QueryInterface, |
| BitmapLockImpl_AddRef, |
| BitmapLockImpl_Release, |
| BitmapLockImpl_GetSize, |
| BitmapLockImpl_GetStride, |
| BitmapLockImpl_GetDataPointer, |
| BitmapLockImpl_GetPixelFormat |
| }; |
| |
| static HRESULT WINAPI BitmapImpl_QueryInterface(IWICBitmap *iface, REFIID iid, |
| void **ppv) |
| { |
| BitmapImpl *This = impl_from_IWICBitmap(iface); |
| TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); |
| |
| if (!ppv) return E_INVALIDARG; |
| |
| if (IsEqualIID(&IID_IUnknown, iid) || |
| IsEqualIID(&IID_IWICBitmapSource, iid) || |
| IsEqualIID(&IID_IWICBitmap, iid)) |
| { |
| *ppv = &This->IWICBitmap_iface; |
| } |
| else if (IsEqualIID(&IID_IMILBitmapSource, iid)) |
| { |
| *ppv = &This->IMILBitmapSource_iface; |
| } |
| else |
| { |
| *ppv = NULL; |
| return E_NOINTERFACE; |
| } |
| |
| IUnknown_AddRef((IUnknown*)*ppv); |
| return S_OK; |
| } |
| |
| static ULONG WINAPI BitmapImpl_AddRef(IWICBitmap *iface) |
| { |
| BitmapImpl *This = impl_from_IWICBitmap(iface); |
| ULONG ref = InterlockedIncrement(&This->ref); |
| |
| TRACE("(%p) refcount=%u\n", iface, ref); |
| |
| return ref; |
| } |
| |
| static ULONG WINAPI BitmapImpl_Release(IWICBitmap *iface) |
| { |
| BitmapImpl *This = impl_from_IWICBitmap(iface); |
| ULONG ref = InterlockedDecrement(&This->ref); |
| |
| TRACE("(%p) refcount=%u\n", iface, ref); |
| |
| if (ref == 0) |
| { |
| if (This->palette) IWICPalette_Release(This->palette); |
| This->cs.DebugInfo->Spare[0] = 0; |
| DeleteCriticalSection(&This->cs); |
| HeapFree(GetProcessHeap(), 0, This->data); |
| HeapFree(GetProcessHeap(), 0, This); |
| } |
| |
| return ref; |
| } |
| |
| static HRESULT WINAPI BitmapImpl_GetSize(IWICBitmap *iface, |
| UINT *puiWidth, UINT *puiHeight) |
| { |
| BitmapImpl *This = impl_from_IWICBitmap(iface); |
| TRACE("(%p,%p,%p)\n", iface, puiWidth, puiHeight); |
| |
| if (!puiWidth || !puiHeight) |
| return E_INVALIDARG; |
| |
| *puiWidth = This->width; |
| *puiHeight = This->height; |
| |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI BitmapImpl_GetPixelFormat(IWICBitmap *iface, |
| WICPixelFormatGUID *pPixelFormat) |
| { |
| BitmapImpl *This = impl_from_IWICBitmap(iface); |
| TRACE("(%p,%p)\n", iface, pPixelFormat); |
| |
| if (!pPixelFormat) |
| return E_INVALIDARG; |
| |
| memcpy(pPixelFormat, &This->pixelformat, sizeof(GUID)); |
| |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI BitmapImpl_GetResolution(IWICBitmap *iface, |
| double *pDpiX, double *pDpiY) |
| { |
| BitmapImpl *This = impl_from_IWICBitmap(iface); |
| TRACE("(%p,%p,%p)\n", iface, pDpiX, pDpiY); |
| |
| if (!pDpiX || !pDpiY) |
| return E_INVALIDARG; |
| |
| EnterCriticalSection(&This->cs); |
| *pDpiX = This->dpix; |
| *pDpiY = This->dpiy; |
| LeaveCriticalSection(&This->cs); |
| |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI BitmapImpl_CopyPalette(IWICBitmap *iface, |
| IWICPalette *pIPalette) |
| { |
| BitmapImpl *This = impl_from_IWICBitmap(iface); |
| TRACE("(%p,%p)\n", iface, pIPalette); |
| |
| if (!This->palette_set) |
| return WINCODEC_ERR_PALETTEUNAVAILABLE; |
| |
| return IWICPalette_InitializeFromPalette(pIPalette, This->palette); |
| } |
| |
| static HRESULT WINAPI BitmapImpl_CopyPixels(IWICBitmap *iface, |
| const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer) |
| { |
| BitmapImpl *This = impl_from_IWICBitmap(iface); |
| TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer); |
| |
| return copy_pixels(This->bpp, This->data, This->width, This->height, |
| This->stride, prc, cbStride, cbBufferSize, pbBuffer); |
| } |
| |
| static HRESULT WINAPI BitmapImpl_Lock(IWICBitmap *iface, const WICRect *prcLock, |
| DWORD flags, IWICBitmapLock **ppILock) |
| { |
| BitmapImpl *This = impl_from_IWICBitmap(iface); |
| BitmapLockImpl *result; |
| WICRect rc; |
| |
| TRACE("(%p,%p,%x,%p)\n", iface, prcLock, flags, ppILock); |
| |
| if (!(flags & (WICBitmapLockRead|WICBitmapLockWrite)) || !ppILock) |
| return E_INVALIDARG; |
| |
| if (!prcLock) |
| { |
| rc.X = rc.Y = 0; |
| rc.Width = This->width; |
| rc.Height = This->height; |
| prcLock = &rc; |
| } |
| else if (prcLock->X >= This->width || prcLock->Y >= This->height || |
| prcLock->X + prcLock->Width > This->width || |
| prcLock->Y + prcLock->Height > This->height || |
| prcLock->Width <= 0 || prcLock->Height <= 0) |
| return E_INVALIDARG; |
| else if (((prcLock->X * This->bpp) % 8) != 0) |
| { |
| FIXME("Cannot lock at an X coordinate not at a full byte\n"); |
| return E_FAIL; |
| } |
| |
| result = HeapAlloc(GetProcessHeap(), 0, sizeof(BitmapLockImpl)); |
| if (!result) |
| return E_OUTOFMEMORY; |
| |
| if (!BitmapImpl_AcquireLock(This, flags & WICBitmapLockWrite)) |
| { |
| HeapFree(GetProcessHeap(), 0, result); |
| return WINCODEC_ERR_ALREADYLOCKED; |
| } |
| |
| result->IWICBitmapLock_iface.lpVtbl = &BitmapLockImpl_Vtbl; |
| result->ref = 1; |
| result->parent = This; |
| result->width = prcLock->Width; |
| result->height = prcLock->Height; |
| result->data = This->data + This->stride * prcLock->Y + |
| (This->bpp * prcLock->X)/8; |
| |
| IWICBitmap_AddRef(&This->IWICBitmap_iface); |
| *ppILock = &result->IWICBitmapLock_iface; |
| |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI BitmapImpl_SetPalette(IWICBitmap *iface, IWICPalette *pIPalette) |
| { |
| BitmapImpl *This = impl_from_IWICBitmap(iface); |
| HRESULT hr; |
| |
| TRACE("(%p,%p)\n", iface, pIPalette); |
| |
| if (!This->palette) |
| { |
| IWICPalette *new_palette; |
| hr = PaletteImpl_Create(&new_palette); |
| |
| if (FAILED(hr)) return hr; |
| |
| if (InterlockedCompareExchangePointer((void**)&This->palette, new_palette, NULL)) |
| { |
| /* someone beat us to it */ |
| IWICPalette_Release(new_palette); |
| } |
| } |
| |
| hr = IWICPalette_InitializeFromPalette(This->palette, pIPalette); |
| |
| if (SUCCEEDED(hr)) |
| This->palette_set = 1; |
| |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI BitmapImpl_SetResolution(IWICBitmap *iface, |
| double dpiX, double dpiY) |
| { |
| BitmapImpl *This = impl_from_IWICBitmap(iface); |
| TRACE("(%p,%f,%f)\n", iface, dpiX, dpiY); |
| |
| EnterCriticalSection(&This->cs); |
| This->dpix = dpiX; |
| This->dpiy = dpiY; |
| LeaveCriticalSection(&This->cs); |
| |
| return S_OK; |
| } |
| |
| static const IWICBitmapVtbl BitmapImpl_Vtbl = { |
| BitmapImpl_QueryInterface, |
| BitmapImpl_AddRef, |
| BitmapImpl_Release, |
| BitmapImpl_GetSize, |
| BitmapImpl_GetPixelFormat, |
| BitmapImpl_GetResolution, |
| BitmapImpl_CopyPalette, |
| BitmapImpl_CopyPixels, |
| BitmapImpl_Lock, |
| BitmapImpl_SetPalette, |
| BitmapImpl_SetResolution |
| }; |
| |
| static HRESULT WINAPI IMILBitmapImpl_QueryInterface(IMILBitmapSource *iface, REFIID iid, |
| void **ppv) |
| { |
| BitmapImpl *This = impl_from_IMILBitmapSource(iface); |
| TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); |
| |
| if (!ppv) return E_INVALIDARG; |
| |
| if (IsEqualIID(&IID_IUnknown, iid) || |
| IsEqualIID(&IID_IMILBitmapSource, iid)) |
| { |
| IUnknown_AddRef(&This->IMILBitmapSource_iface); |
| *ppv = &This->IMILBitmapSource_iface; |
| return S_OK; |
| } |
| |
| *ppv = NULL; |
| return E_NOINTERFACE; |
| } |
| |
| static ULONG WINAPI IMILBitmapImpl_AddRef(IMILBitmapSource *iface) |
| { |
| BitmapImpl *This = impl_from_IMILBitmapSource(iface); |
| return IWICBitmap_AddRef(&This->IWICBitmap_iface); |
| } |
| |
| static ULONG WINAPI IMILBitmapImpl_Release(IMILBitmapSource *iface) |
| { |
| BitmapImpl *This = impl_from_IMILBitmapSource(iface); |
| return IWICBitmap_Release(&This->IWICBitmap_iface); |
| } |
| |
| static HRESULT WINAPI IMILBitmapImpl_GetSize(IMILBitmapSource *iface, |
| UINT *width, UINT *height) |
| { |
| BitmapImpl *This = impl_from_IMILBitmapSource(iface); |
| return IWICBitmap_GetSize(&This->IWICBitmap_iface, width, height); |
| } |
| |
| static const struct |
| { |
| const GUID *WIC_format; |
| int enum_format; |
| } pixel_fmt_map[] = |
| { |
| { &GUID_WICPixelFormatDontCare, 0 }, |
| { &GUID_WICPixelFormat1bppIndexed, 1 }, |
| { &GUID_WICPixelFormat2bppIndexed, 2 }, |
| { &GUID_WICPixelFormat4bppIndexed, 3 }, |
| { &GUID_WICPixelFormat8bppIndexed, 4 }, |
| { &GUID_WICPixelFormatBlackWhite, 5 }, |
| { &GUID_WICPixelFormat2bppGray, 6 }, |
| { &GUID_WICPixelFormat4bppGray, 7 }, |
| { &GUID_WICPixelFormat8bppGray, 8 }, |
| { &GUID_WICPixelFormat16bppBGR555, 9 }, |
| { &GUID_WICPixelFormat16bppBGR565, 0x0a }, |
| { &GUID_WICPixelFormat16bppGray, 0x0b }, |
| { &GUID_WICPixelFormat24bppBGR, 0x0c }, |
| { &GUID_WICPixelFormat24bppRGB, 0x0d }, |
| { &GUID_WICPixelFormat32bppBGR, 0x0e }, |
| { &GUID_WICPixelFormat32bppBGRA, 0x0f }, |
| { &GUID_WICPixelFormat32bppPBGRA, 0x10 }, |
| { &GUID_WICPixelFormat48bppRGB, 0x15 }, |
| { &GUID_WICPixelFormat64bppRGBA, 0x16 }, |
| { &GUID_WICPixelFormat64bppPRGBA, 0x17 }, |
| { &GUID_WICPixelFormat32bppCMYK, 0x1c } |
| }; |
| |
| static HRESULT WINAPI IMILBitmapImpl_GetPixelFormat(IMILBitmapSource *iface, |
| int *format) |
| { |
| BitmapImpl *This = impl_from_IMILBitmapSource(iface); |
| int i; |
| |
| TRACE("(%p,%p)\n", iface, format); |
| |
| if (!format) return E_INVALIDARG; |
| |
| *format = 0; |
| |
| for (i = 0; i < sizeof(pixel_fmt_map)/sizeof(pixel_fmt_map[0]); i++) |
| { |
| if (IsEqualGUID(pixel_fmt_map[i].WIC_format, &This->pixelformat)) |
| { |
| *format = pixel_fmt_map[i].enum_format; |
| break; |
| } |
| } |
| |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI IMILBitmapImpl_GetResolution(IMILBitmapSource *iface, |
| double *dpix, double *dpiy) |
| { |
| BitmapImpl *This = impl_from_IMILBitmapSource(iface); |
| return IWICBitmap_GetResolution(&This->IWICBitmap_iface, dpix, dpiy); |
| } |
| |
| static HRESULT WINAPI IMILBitmapImpl_CopyPalette(IMILBitmapSource *iface, |
| IWICPalette *palette) |
| { |
| BitmapImpl *This = impl_from_IMILBitmapSource(iface); |
| return IWICBitmap_CopyPalette(&This->IWICBitmap_iface, palette); |
| } |
| |
| static HRESULT WINAPI IMILBitmapImpl_CopyPixels(IMILBitmapSource *iface, |
| const WICRect *rc, UINT stride, UINT size, BYTE *buffer) |
| { |
| BitmapImpl *This = impl_from_IMILBitmapSource(iface); |
| return IWICBitmap_CopyPixels(&This->IWICBitmap_iface, rc, stride, size, buffer); |
| } |
| |
| static HRESULT WINAPI IMILBitmapImpl_UnknownMethod1(IMILBitmapSource *iface, void **ppv) |
| { |
| BitmapImpl *This = impl_from_IMILBitmapSource(iface); |
| |
| TRACE("(%p,%p)\n", iface, ppv); |
| |
| if (!ppv) return E_INVALIDARG; |
| |
| IUnknown_AddRef(&This->IMILUnknown1_iface); |
| *ppv = &This->IMILUnknown1_iface; |
| |
| return S_OK; |
| } |
| |
| static const IMILBitmapSourceVtbl IMILBitmapImpl_Vtbl = |
| { |
| IMILBitmapImpl_QueryInterface, |
| IMILBitmapImpl_AddRef, |
| IMILBitmapImpl_Release, |
| IMILBitmapImpl_GetSize, |
| IMILBitmapImpl_GetPixelFormat, |
| IMILBitmapImpl_GetResolution, |
| IMILBitmapImpl_CopyPalette, |
| IMILBitmapImpl_CopyPixels, |
| IMILBitmapImpl_UnknownMethod1, |
| }; |
| |
| static HRESULT WINAPI IMILUnknown1Impl_QueryInterface(IMILUnknown1 *iface, REFIID iid, |
| void **ppv) |
| { |
| BitmapImpl *This = impl_from_IMILUnknown1(iface); |
| |
| TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); |
| |
| if (!ppv) return E_INVALIDARG; |
| |
| if (IsEqualIID(&IID_IUnknown, iid)) |
| { |
| IUnknown_AddRef(&This->IMILUnknown1_iface); |
| *ppv = iface; |
| return S_OK; |
| } |
| |
| return IWICBitmap_QueryInterface(&This->IWICBitmap_iface, iid, ppv); |
| } |
| |
| static ULONG WINAPI IMILUnknown1Impl_AddRef(IMILUnknown1 *iface) |
| { |
| BitmapImpl *This = impl_from_IMILUnknown1(iface); |
| return IWICBitmap_AddRef(&This->IWICBitmap_iface); |
| } |
| |
| static ULONG WINAPI IMILUnknown1Impl_Release(IMILUnknown1 *iface) |
| { |
| BitmapImpl *This = impl_from_IMILUnknown1(iface); |
| return IWICBitmap_Release(&This->IWICBitmap_iface); |
| } |
| |
| static const IMILUnknown1Vtbl IMILUnknown1Impl_Vtbl = |
| { |
| IMILUnknown1Impl_QueryInterface, |
| IMILUnknown1Impl_AddRef, |
| IMILUnknown1Impl_Release, |
| }; |
| |
| static HRESULT WINAPI IMILUnknown2Impl_QueryInterface(IMILUnknown2 *iface, REFIID iid, |
| void **ppv) |
| { |
| BitmapImpl *This = impl_from_IMILUnknown2(iface); |
| |
| TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); |
| |
| if (!ppv) return E_INVALIDARG; |
| |
| if (IsEqualIID(&IID_IUnknown, iid)) |
| { |
| IUnknown_AddRef(&This->IMILUnknown2_iface); |
| *ppv = iface; |
| return S_OK; |
| } |
| |
| return IWICBitmap_QueryInterface(&This->IWICBitmap_iface, iid, ppv); |
| } |
| |
| static ULONG WINAPI IMILUnknown2Impl_AddRef(IMILUnknown2 *iface) |
| { |
| BitmapImpl *This = impl_from_IMILUnknown2(iface); |
| return IWICBitmap_AddRef(&This->IWICBitmap_iface); |
| } |
| |
| static ULONG WINAPI IMILUnknown2Impl_Release(IMILUnknown2 *iface) |
| { |
| BitmapImpl *This = impl_from_IMILUnknown2(iface); |
| return IWICBitmap_Release(&This->IWICBitmap_iface); |
| } |
| |
| static HRESULT WINAPI IMILUnknown2Impl_UnknownMethod1(IMILUnknown2 *iface, void *arg1, void *arg2) |
| { |
| FIXME("(%p,%p,%p): stub\n", iface, arg1, arg2); |
| return E_NOTIMPL; |
| } |
| |
| static const IMILUnknown2Vtbl IMILUnknown2Impl_Vtbl = |
| { |
| IMILUnknown2Impl_QueryInterface, |
| IMILUnknown2Impl_AddRef, |
| IMILUnknown2Impl_Release, |
| IMILUnknown2Impl_UnknownMethod1, |
| }; |
| |
| HRESULT BitmapImpl_Create(UINT uiWidth, UINT uiHeight, |
| UINT stride, UINT datasize, BYTE *bits, |
| REFWICPixelFormatGUID pixelFormat, WICBitmapCreateCacheOption option, |
| IWICBitmap **ppIBitmap) |
| { |
| HRESULT hr; |
| BitmapImpl *This; |
| BYTE *data; |
| UINT bpp; |
| |
| hr = get_pixelformat_bpp(pixelFormat, &bpp); |
| if (FAILED(hr)) return hr; |
| |
| if (!stride) stride = (((bpp*uiWidth)+31)/32)*4; |
| if (!datasize) datasize = stride * uiHeight; |
| |
| if (datasize < stride * uiHeight) return WINCODEC_ERR_INSUFFICIENTBUFFER; |
| if (stride < ((bpp*uiWidth)+7)/8) return E_INVALIDARG; |
| |
| This = HeapAlloc(GetProcessHeap(), 0, sizeof(BitmapImpl)); |
| data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, datasize); |
| if (!This || !data) |
| { |
| HeapFree(GetProcessHeap(), 0, This); |
| HeapFree(GetProcessHeap(), 0, data); |
| return E_OUTOFMEMORY; |
| } |
| if (bits) memcpy(data, bits, datasize); |
| |
| This->IWICBitmap_iface.lpVtbl = &BitmapImpl_Vtbl; |
| This->IMILBitmapSource_iface.lpVtbl = &IMILBitmapImpl_Vtbl; |
| This->IMILUnknown1_iface.lpVtbl = &IMILUnknown1Impl_Vtbl; |
| This->IMILUnknown2_iface.lpVtbl = &IMILUnknown2Impl_Vtbl; |
| This->ref = 1; |
| This->palette = NULL; |
| This->palette_set = 0; |
| This->lock = 0; |
| This->data = data; |
| This->width = uiWidth; |
| This->height = uiHeight; |
| This->stride = stride; |
| This->bpp = bpp; |
| memcpy(&This->pixelformat, pixelFormat, sizeof(GUID)); |
| This->dpix = This->dpiy = 0.0; |
| InitializeCriticalSection(&This->cs); |
| This->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": BitmapImpl.lock"); |
| |
| *ppIBitmap = &This->IWICBitmap_iface; |
| |
| return S_OK; |
| } |