diff --git a/dlls/windowscodecs/bitmap.c b/dlls/windowscodecs/bitmap.c index 1f8d87d28d4..c5bd8700b9a 100644 --- a/dlls/windowscodecs/bitmap.c +++ b/dlls/windowscodecs/bitmap.c @@ -38,13 +38,151 @@ typedef struct BitmapImpl { LONG ref; IWICPalette *palette; int palette_set; + LONG lock; /* 0 if not locked, -1 if locked for writing, count if locked for reading */ } BitmapImpl; +typedef struct BitmapLockImpl { + IWICBitmapLock IWICBitmapLock_iface; + LONG ref; + BitmapImpl *parent; +} BitmapLockImpl; + static inline BitmapImpl *impl_from_IWICBitmap(IWICBitmap *iface) { return CONTAINING_RECORD(iface, BitmapImpl, IWICBitmap_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) +{ + FIXME("(%p,%p,%p)\n", iface, puiWidth, puiHeight); + + return E_NOTIMPL; +} + +static HRESULT WINAPI BitmapLockImpl_GetStride(IWICBitmapLock *iface, + UINT *pcbStride) +{ + FIXME("(%p,%p)\n", iface, pcbStride); + + return E_NOTIMPL; +} + +static HRESULT WINAPI BitmapLockImpl_GetDataPointer(IWICBitmapLock *iface, + UINT *pcbBufferSize, BYTE **ppbData) +{ + FIXME("(%p,%p,%p)\n", iface, pcbBufferSize, ppbData); + + return E_NOTIMPL; +} + +static HRESULT WINAPI BitmapLockImpl_GetPixelFormat(IWICBitmapLock *iface, + WICPixelFormatGUID *pPixelFormat) +{ + FIXME("(%p,%p)\n", iface, pPixelFormat); + + return E_NOTIMPL; +} + +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) { @@ -142,9 +280,32 @@ static HRESULT WINAPI BitmapImpl_CopyPixels(IWICBitmap *iface, static HRESULT WINAPI BitmapImpl_Lock(IWICBitmap *iface, const WICRect *prcLock, DWORD flags, IWICBitmapLock **ppILock) { - FIXME("(%p,%p,%x,%p)\n", iface, prcLock, flags, ppILock); + BitmapImpl *This = impl_from_IWICBitmap(iface); + BitmapLockImpl *result; - return E_NOTIMPL; + TRACE("(%p,%p,%x,%p)\n", iface, prcLock, flags, ppILock); + + if (!(flags & (WICBitmapLockRead|WICBitmapLockWrite)) || !ppILock) + return E_INVALIDARG; + + 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; + + IWICBitmap_AddRef(&This->IWICBitmap_iface); + *ppILock = &result->IWICBitmapLock_iface; + + return S_OK; } static HRESULT WINAPI BitmapImpl_SetPalette(IWICBitmap *iface, IWICPalette *pIPalette) @@ -211,6 +372,7 @@ HRESULT BitmapImpl_Create(UINT uiWidth, UINT uiHeight, This->ref = 1; This->palette = NULL; This->palette_set = 0; + This->lock = 0; *ppIBitmap = &This->IWICBitmap_iface; diff --git a/dlls/windowscodecs/tests/bitmap.c b/dlls/windowscodecs/tests/bitmap.c index a5577a153a7..cc80f0bbf98 100644 --- a/dlls/windowscodecs/tests/bitmap.c +++ b/dlls/windowscodecs/tests/bitmap.c @@ -90,31 +90,30 @@ static void test_createbitmap(void) for (i=0; i<27; i++) ok(returned_data[i] == 0, "returned_data[%i] == %i\n", i, returned_data[i]); -todo_wine { /* Invalid lock rects */ rc.X = rc.Y = 0; rc.Width = 4; rc.Height = 3; hr = IWICBitmap_Lock(bitmap, &rc, WICBitmapLockRead, &lock); - ok(hr == E_INVALIDARG, "IWICBitmap_Lock failed hr=%x\n", hr); + todo_wine ok(hr == E_INVALIDARG, "IWICBitmap_Lock failed hr=%x\n", hr); if (SUCCEEDED(hr)) IWICBitmapLock_Release(lock); rc.Width = 3; rc.Height = 4; hr = IWICBitmap_Lock(bitmap, &rc, WICBitmapLockRead, &lock); - ok(hr == E_INVALIDARG, "IWICBitmap_Lock failed hr=%x\n", hr); + todo_wine ok(hr == E_INVALIDARG, "IWICBitmap_Lock failed hr=%x\n", hr); if (SUCCEEDED(hr)) IWICBitmapLock_Release(lock); rc.Height = 3; rc.X = 4; hr = IWICBitmap_Lock(bitmap, &rc, WICBitmapLockRead, &lock); - ok(hr == E_INVALIDARG, "IWICBitmap_Lock failed hr=%x\n", hr); + todo_wine ok(hr == E_INVALIDARG, "IWICBitmap_Lock failed hr=%x\n", hr); if (SUCCEEDED(hr)) IWICBitmapLock_Release(lock); rc.X = 0; rc.Y = 4; hr = IWICBitmap_Lock(bitmap, &rc, WICBitmapLockRead, &lock); - ok(hr == E_INVALIDARG, "IWICBitmap_Lock failed hr=%x\n", hr); + todo_wine ok(hr == E_INVALIDARG, "IWICBitmap_Lock failed hr=%x\n", hr); if (SUCCEEDED(hr)) IWICBitmapLock_Release(lock); /* NULL lock rect */ @@ -125,9 +124,9 @@ todo_wine { { /* entire bitmap is locked */ hr = IWICBitmapLock_GetSize(lock, &width, &height); - ok(hr == S_OK, "IWICBitmapLock_GetSize failed hr=%x\n", hr); - ok(width == 3, "got %d, expected 3\n", width); - ok(height == 3, "got %d, expected 3\n", height); + todo_wine ok(hr == S_OK, "IWICBitmapLock_GetSize failed hr=%x\n", hr); + todo_wine ok(width == 3, "got %d, expected 3\n", width); + todo_wine ok(height == 3, "got %d, expected 3\n", height); IWICBitmapLock_Release(lock); } @@ -141,25 +140,25 @@ todo_wine { if (SUCCEEDED(hr)) { hr = IWICBitmapLock_GetStride(lock, &lock_buffer_stride); - ok(hr == S_OK, "IWICBitmapLock_GetStride failed hr=%x\n", hr); + todo_wine ok(hr == S_OK, "IWICBitmapLock_GetStride failed hr=%x\n", hr); /* stride is divisible by 4 */ - ok(lock_buffer_stride == 12, "got %i, expected 12\n", lock_buffer_stride); + todo_wine ok(lock_buffer_stride == 12, "got %i, expected 12\n", lock_buffer_stride); hr = IWICBitmapLock_GetDataPointer(lock, &lock_buffer_size, &lock_buffer); - ok(hr == S_OK, "IWICBitmapLock_GetDataPointer failed hr=%x\n", hr); + todo_wine ok(hr == S_OK, "IWICBitmapLock_GetDataPointer failed hr=%x\n", hr); /* buffer size does not include padding from the last row */ - ok(lock_buffer_size == 33, "got %i, expected 33\n", lock_buffer_size); - ok(lock_buffer != NULL, "got NULL data pointer\n"); + todo_wine ok(lock_buffer_size == 33, "got %i, expected 33\n", lock_buffer_size); + todo_wine ok(lock_buffer != NULL, "got NULL data pointer\n"); base_lock_buffer = lock_buffer; hr = IWICBitmapLock_GetPixelFormat(lock, &pixelformat); - ok(hr == S_OK, "IWICBitmapLock_GetPixelFormat failed hr=%x\n", hr); - ok(IsEqualGUID(&pixelformat, &GUID_WICPixelFormat24bppBGR), "unexpected pixel format\n"); + todo_wine ok(hr == S_OK, "IWICBitmapLock_GetPixelFormat failed hr=%x\n", hr); + todo_wine ok(IsEqualGUID(&pixelformat, &GUID_WICPixelFormat24bppBGR), "unexpected pixel format\n"); hr = IWICBitmapLock_GetSize(lock, &width, &height); - ok(hr == S_OK, "IWICBitmapLock_GetSize failed hr=%x\n", hr); - ok(width == 3, "got %d, expected 3\n", width); - ok(height == 3, "got %d, expected 3\n", height); + todo_wine ok(hr == S_OK, "IWICBitmapLock_GetSize failed hr=%x\n", hr); + todo_wine ok(width == 3, "got %d, expected 3\n", width); + todo_wine ok(height == 3, "got %d, expected 3\n", height); /* We can have multiple simultaneous read locks */ hr = IWICBitmap_Lock(bitmap, &rc, WICBitmapLockRead, &lock2); @@ -168,8 +167,8 @@ todo_wine { if (SUCCEEDED(hr)) { hr = IWICBitmapLock_GetDataPointer(lock2, &lock_buffer_size, &lock_buffer); - ok(hr == S_OK, "IWICBitmapLock_GetDataPointer failed hr=%x\n", hr); - ok(lock_buffer_size == 33, "got %i, expected 33\n", lock_buffer_size); + todo_wine ok(hr == S_OK, "IWICBitmapLock_GetDataPointer failed hr=%x\n", hr); + todo_wine ok(lock_buffer_size == 33, "got %i, expected 33\n", lock_buffer_size); ok(lock_buffer == base_lock_buffer, "got %p, expected %p\n", lock_buffer, base_lock_buffer); IWICBitmapLock_Release(lock2); @@ -183,18 +182,21 @@ todo_wine { } /* But we don't need a write lock to write */ - for (i=0; i<3; i++) - memcpy(base_lock_buffer + lock_buffer_stride*i, bitmap_data + i*9, 9); + if (base_lock_buffer) + { + for (i=0; i<3; i++) + memcpy(base_lock_buffer + lock_buffer_stride*i, bitmap_data + i*9, 9); + } IWICBitmapLock_Release(lock); } /* test that the data we wrote is returned by CopyPixels */ hr = IWICBitmap_CopyPixels(bitmap, NULL, 9, 27, returned_data); - ok(hr == S_OK, "IWICBitmap_CopyPixels failed hr=%x\n", hr); + todo_wine ok(hr == S_OK, "IWICBitmap_CopyPixels failed hr=%x\n", hr); for (i=0; i<27; i++) - ok(returned_data[i] == bitmap_data[i], "returned_data[%i] == %i\n", i, returned_data[i]); + todo_wine ok(returned_data[i] == bitmap_data[i], "returned_data[%i] == %i\n", i, returned_data[i]); /* try a valid partial rect, and write mode */ rc.X = 2; @@ -217,26 +219,27 @@ todo_wine { } hr = IWICBitmapLock_GetStride(lock, &lock_buffer_stride); - ok(hr == S_OK, "IWICBitmapLock_GetStride failed hr=%x\n", hr); - ok(lock_buffer_stride == 12, "got %i, expected 12\n", lock_buffer_stride); + todo_wine ok(hr == S_OK, "IWICBitmapLock_GetStride failed hr=%x\n", hr); + todo_wine ok(lock_buffer_stride == 12, "got %i, expected 12\n", lock_buffer_stride); hr = IWICBitmapLock_GetDataPointer(lock, &lock_buffer_size, &lock_buffer); - ok(hr == S_OK, "IWICBitmapLock_GetDataPointer failed hr=%x\n", hr); - ok(lock_buffer_size == 15, "got %i, expected 15\n", lock_buffer_size); - ok(lock_buffer == base_lock_buffer+6, "got %p, expected %p+6\n", lock_buffer, base_lock_buffer); + todo_wine ok(hr == S_OK, "IWICBitmapLock_GetDataPointer failed hr=%x\n", hr); + todo_wine ok(lock_buffer_size == 15, "got %i, expected 15\n", lock_buffer_size); + todo_wine ok(lock_buffer == base_lock_buffer+6, "got %p, expected %p+6\n", lock_buffer, base_lock_buffer); hr = IWICBitmapLock_GetPixelFormat(lock, &pixelformat); - ok(hr == S_OK, "IWICBitmapLock_GetPixelFormat failed hr=%x\n", hr); - ok(IsEqualGUID(&pixelformat, &GUID_WICPixelFormat24bppBGR), "unexpected pixel format\n"); + todo_wine ok(hr == S_OK, "IWICBitmapLock_GetPixelFormat failed hr=%x\n", hr); + todo_wine ok(IsEqualGUID(&pixelformat, &GUID_WICPixelFormat24bppBGR), "unexpected pixel format\n"); hr = IWICBitmapLock_GetSize(lock, &width, &height); - ok(hr == S_OK, "IWICBitmapLock_GetSize failed hr=%x\n", hr); - ok(width == 1, "got %d, expected 1\n", width); - ok(height == 2, "got %d, expected 2\n", height); + todo_wine ok(hr == S_OK, "IWICBitmapLock_GetSize failed hr=%x\n", hr); + todo_wine ok(width == 1, "got %d, expected 1\n", width); + todo_wine ok(height == 2, "got %d, expected 2\n", height); IWICBitmapLock_Release(lock); } +todo_wine { hr = IWICBitmap_GetPixelFormat(bitmap, &pixelformat); ok(hr == S_OK, "IWICBitmap_GetPixelFormat failed hr=%x\n", hr); ok(IsEqualGUID(&pixelformat, &GUID_WICPixelFormat24bppBGR), "unexpected pixel format\n");