2 * Copyright 2012 Vincent Povirk for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
30 #include "wincodecs_private.h"
32 #include "wine/debug.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs
);
36 typedef struct BitmapImpl
{
37 IWICBitmap IWICBitmap_iface
;
41 LONG lock
; /* 0 if not locked, -1 if locked for writing, count if locked for reading */
46 WICPixelFormatGUID pixelformat
;
51 typedef struct BitmapLockImpl
{
52 IWICBitmapLock IWICBitmapLock_iface
;
59 static inline BitmapImpl
*impl_from_IWICBitmap(IWICBitmap
*iface
)
61 return CONTAINING_RECORD(iface
, BitmapImpl
, IWICBitmap_iface
);
64 static inline BitmapLockImpl
*impl_from_IWICBitmapLock(IWICBitmapLock
*iface
)
66 return CONTAINING_RECORD(iface
, BitmapLockImpl
, IWICBitmapLock_iface
);
69 static BOOL
BitmapImpl_AcquireLock(BitmapImpl
*This
, int write
)
73 return 0 == InterlockedCompareExchange(&This
->lock
, -1, 0);
79 LONG prev_val
= This
->lock
;
82 if (prev_val
== InterlockedCompareExchange(&This
->lock
, prev_val
+1, prev_val
))
88 static void BitmapImpl_ReleaseLock(BitmapImpl
*This
)
92 LONG prev_val
= This
->lock
, new_val
;
96 new_val
= prev_val
- 1;
97 if (prev_val
== InterlockedCompareExchange(&This
->lock
, new_val
, prev_val
))
103 static HRESULT WINAPI
BitmapLockImpl_QueryInterface(IWICBitmapLock
*iface
, REFIID iid
,
106 BitmapLockImpl
*This
= impl_from_IWICBitmapLock(iface
);
107 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
109 if (!ppv
) return E_INVALIDARG
;
111 if (IsEqualIID(&IID_IUnknown
, iid
) ||
112 IsEqualIID(&IID_IWICBitmapLock
, iid
))
114 *ppv
= &This
->IWICBitmapLock_iface
;
119 return E_NOINTERFACE
;
122 IUnknown_AddRef((IUnknown
*)*ppv
);
126 static ULONG WINAPI
BitmapLockImpl_AddRef(IWICBitmapLock
*iface
)
128 BitmapLockImpl
*This
= impl_from_IWICBitmapLock(iface
);
129 ULONG ref
= InterlockedIncrement(&This
->ref
);
131 TRACE("(%p) refcount=%u\n", iface
, ref
);
136 static ULONG WINAPI
BitmapLockImpl_Release(IWICBitmapLock
*iface
)
138 BitmapLockImpl
*This
= impl_from_IWICBitmapLock(iface
);
139 ULONG ref
= InterlockedDecrement(&This
->ref
);
141 TRACE("(%p) refcount=%u\n", iface
, ref
);
145 BitmapImpl_ReleaseLock(This
->parent
);
146 IWICBitmap_Release(&This
->parent
->IWICBitmap_iface
);
147 HeapFree(GetProcessHeap(), 0, This
);
153 static HRESULT WINAPI
BitmapLockImpl_GetSize(IWICBitmapLock
*iface
,
154 UINT
*puiWidth
, UINT
*puiHeight
)
156 BitmapLockImpl
*This
= impl_from_IWICBitmapLock(iface
);
157 TRACE("(%p,%p,%p)\n", iface
, puiWidth
, puiHeight
);
159 if (!puiWidth
|| !puiHeight
)
162 *puiWidth
= This
->width
;
163 *puiHeight
= This
->height
;
168 static HRESULT WINAPI
BitmapLockImpl_GetStride(IWICBitmapLock
*iface
,
171 BitmapLockImpl
*This
= impl_from_IWICBitmapLock(iface
);
172 TRACE("(%p,%p)\n", iface
, pcbStride
);
177 *pcbStride
= This
->parent
->stride
;
182 static HRESULT WINAPI
BitmapLockImpl_GetDataPointer(IWICBitmapLock
*iface
,
183 UINT
*pcbBufferSize
, BYTE
**ppbData
)
185 BitmapLockImpl
*This
= impl_from_IWICBitmapLock(iface
);
186 TRACE("(%p,%p,%p)\n", iface
, pcbBufferSize
, ppbData
);
188 if (!pcbBufferSize
|| !ppbData
)
191 *pcbBufferSize
= This
->parent
->stride
* (This
->height
- 1) +
192 ((This
->parent
->bpp
* This
->width
) + 7)/8;
193 *ppbData
= This
->data
;
198 static HRESULT WINAPI
BitmapLockImpl_GetPixelFormat(IWICBitmapLock
*iface
,
199 WICPixelFormatGUID
*pPixelFormat
)
201 BitmapLockImpl
*This
= impl_from_IWICBitmapLock(iface
);
202 TRACE("(%p,%p)\n", iface
, pPixelFormat
);
204 return IWICBitmap_GetPixelFormat(&This
->parent
->IWICBitmap_iface
, pPixelFormat
);
207 static const IWICBitmapLockVtbl BitmapLockImpl_Vtbl
= {
208 BitmapLockImpl_QueryInterface
,
209 BitmapLockImpl_AddRef
,
210 BitmapLockImpl_Release
,
211 BitmapLockImpl_GetSize
,
212 BitmapLockImpl_GetStride
,
213 BitmapLockImpl_GetDataPointer
,
214 BitmapLockImpl_GetPixelFormat
217 static HRESULT WINAPI
BitmapImpl_QueryInterface(IWICBitmap
*iface
, REFIID iid
,
220 BitmapImpl
*This
= impl_from_IWICBitmap(iface
);
221 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
223 if (!ppv
) return E_INVALIDARG
;
225 if (IsEqualIID(&IID_IUnknown
, iid
) ||
226 IsEqualIID(&IID_IWICBitmapSource
, iid
) ||
227 IsEqualIID(&IID_IWICBitmap
, iid
))
229 *ppv
= &This
->IWICBitmap_iface
;
234 return E_NOINTERFACE
;
237 IUnknown_AddRef((IUnknown
*)*ppv
);
241 static ULONG WINAPI
BitmapImpl_AddRef(IWICBitmap
*iface
)
243 BitmapImpl
*This
= impl_from_IWICBitmap(iface
);
244 ULONG ref
= InterlockedIncrement(&This
->ref
);
246 TRACE("(%p) refcount=%u\n", iface
, ref
);
251 static ULONG WINAPI
BitmapImpl_Release(IWICBitmap
*iface
)
253 BitmapImpl
*This
= impl_from_IWICBitmap(iface
);
254 ULONG ref
= InterlockedDecrement(&This
->ref
);
256 TRACE("(%p) refcount=%u\n", iface
, ref
);
260 if (This
->palette
) IWICPalette_Release(This
->palette
);
261 This
->cs
.DebugInfo
->Spare
[0] = 0;
262 DeleteCriticalSection(&This
->cs
);
263 HeapFree(GetProcessHeap(), 0, This
->data
);
264 HeapFree(GetProcessHeap(), 0, This
);
270 static HRESULT WINAPI
BitmapImpl_GetSize(IWICBitmap
*iface
,
271 UINT
*puiWidth
, UINT
*puiHeight
)
273 BitmapImpl
*This
= impl_from_IWICBitmap(iface
);
274 TRACE("(%p,%p,%p)\n", iface
, puiWidth
, puiHeight
);
276 if (!puiWidth
|| !puiHeight
)
279 *puiWidth
= This
->width
;
280 *puiHeight
= This
->height
;
285 static HRESULT WINAPI
BitmapImpl_GetPixelFormat(IWICBitmap
*iface
,
286 WICPixelFormatGUID
*pPixelFormat
)
288 BitmapImpl
*This
= impl_from_IWICBitmap(iface
);
289 TRACE("(%p,%p)\n", iface
, pPixelFormat
);
294 memcpy(pPixelFormat
, &This
->pixelformat
, sizeof(GUID
));
299 static HRESULT WINAPI
BitmapImpl_GetResolution(IWICBitmap
*iface
,
300 double *pDpiX
, double *pDpiY
)
302 BitmapImpl
*This
= impl_from_IWICBitmap(iface
);
303 TRACE("(%p,%p,%p)\n", iface
, pDpiX
, pDpiY
);
305 if (!pDpiX
|| !pDpiY
)
308 EnterCriticalSection(&This
->cs
);
311 LeaveCriticalSection(&This
->cs
);
316 static HRESULT WINAPI
BitmapImpl_CopyPalette(IWICBitmap
*iface
,
317 IWICPalette
*pIPalette
)
319 BitmapImpl
*This
= impl_from_IWICBitmap(iface
);
320 TRACE("(%p,%p)\n", iface
, pIPalette
);
322 if (!This
->palette_set
)
323 return WINCODEC_ERR_PALETTEUNAVAILABLE
;
325 return IWICPalette_InitializeFromPalette(pIPalette
, This
->palette
);
328 static HRESULT WINAPI
BitmapImpl_CopyPixels(IWICBitmap
*iface
,
329 const WICRect
*prc
, UINT cbStride
, UINT cbBufferSize
, BYTE
*pbBuffer
)
331 BitmapImpl
*This
= impl_from_IWICBitmap(iface
);
332 TRACE("(%p,%p,%u,%u,%p)\n", iface
, prc
, cbStride
, cbBufferSize
, pbBuffer
);
334 return copy_pixels(This
->bpp
, This
->data
, This
->width
, This
->height
,
335 This
->stride
, prc
, cbStride
, cbBufferSize
, pbBuffer
);
338 static HRESULT WINAPI
BitmapImpl_Lock(IWICBitmap
*iface
, const WICRect
*prcLock
,
339 DWORD flags
, IWICBitmapLock
**ppILock
)
341 BitmapImpl
*This
= impl_from_IWICBitmap(iface
);
342 BitmapLockImpl
*result
;
345 TRACE("(%p,%p,%x,%p)\n", iface
, prcLock
, flags
, ppILock
);
347 if (!(flags
& (WICBitmapLockRead
|WICBitmapLockWrite
)) || !ppILock
)
353 rc
.Width
= This
->width
;
354 rc
.Height
= This
->height
;
357 else if (prcLock
->X
>= This
->width
|| prcLock
->Y
>= This
->height
||
358 prcLock
->X
+ prcLock
->Width
> This
->width
||
359 prcLock
->Y
+ prcLock
->Height
> This
->height
||
360 prcLock
->Width
<= 0 || prcLock
->Height
<= 0)
362 else if (((prcLock
->X
* This
->bpp
) % 8) != 0)
364 FIXME("Cannot lock at an X coordinate not at a full byte\n");
368 result
= HeapAlloc(GetProcessHeap(), 0, sizeof(BitmapLockImpl
));
370 return E_OUTOFMEMORY
;
372 if (!BitmapImpl_AcquireLock(This
, flags
& WICBitmapLockWrite
))
374 HeapFree(GetProcessHeap(), 0, result
);
375 return WINCODEC_ERR_ALREADYLOCKED
;
378 result
->IWICBitmapLock_iface
.lpVtbl
= &BitmapLockImpl_Vtbl
;
380 result
->parent
= This
;
381 result
->width
= prcLock
->Width
;
382 result
->height
= prcLock
->Height
;
383 result
->data
= This
->data
+ This
->stride
* prcLock
->Y
+
384 (This
->bpp
* prcLock
->X
)/8;
386 IWICBitmap_AddRef(&This
->IWICBitmap_iface
);
387 *ppILock
= &result
->IWICBitmapLock_iface
;
392 static HRESULT WINAPI
BitmapImpl_SetPalette(IWICBitmap
*iface
, IWICPalette
*pIPalette
)
394 BitmapImpl
*This
= impl_from_IWICBitmap(iface
);
397 TRACE("(%p,%p)\n", iface
, pIPalette
);
401 IWICPalette
*new_palette
;
402 hr
= PaletteImpl_Create(&new_palette
);
404 if (FAILED(hr
)) return hr
;
406 if (InterlockedCompareExchangePointer((void**)&This
->palette
, new_palette
, NULL
))
408 /* someone beat us to it */
409 IWICPalette_Release(new_palette
);
413 hr
= IWICPalette_InitializeFromPalette(This
->palette
, pIPalette
);
416 This
->palette_set
= 1;
421 static HRESULT WINAPI
BitmapImpl_SetResolution(IWICBitmap
*iface
,
422 double dpiX
, double dpiY
)
424 BitmapImpl
*This
= impl_from_IWICBitmap(iface
);
425 TRACE("(%p,%f,%f)\n", iface
, dpiX
, dpiY
);
427 EnterCriticalSection(&This
->cs
);
430 LeaveCriticalSection(&This
->cs
);
435 static const IWICBitmapVtbl BitmapImpl_Vtbl
= {
436 BitmapImpl_QueryInterface
,
440 BitmapImpl_GetPixelFormat
,
441 BitmapImpl_GetResolution
,
442 BitmapImpl_CopyPalette
,
443 BitmapImpl_CopyPixels
,
445 BitmapImpl_SetPalette
,
446 BitmapImpl_SetResolution
449 HRESULT
BitmapImpl_Create(UINT uiWidth
, UINT uiHeight
,
450 UINT stride
, UINT datasize
, BYTE
*bits
,
451 REFWICPixelFormatGUID pixelFormat
, WICBitmapCreateCacheOption option
,
452 IWICBitmap
**ppIBitmap
)
459 hr
= get_pixelformat_bpp(pixelFormat
, &bpp
);
460 if (FAILED(hr
)) return hr
;
462 if (!stride
) stride
= (((bpp
*uiWidth
)+31)/32)*4;
463 if (!datasize
) datasize
= stride
* uiHeight
;
465 if (datasize
< stride
* uiHeight
) return WINCODEC_ERR_INSUFFICIENTBUFFER
;
466 if (stride
< ((bpp
*uiWidth
)+7)/8) return E_INVALIDARG
;
468 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(BitmapImpl
));
469 data
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, datasize
);
472 HeapFree(GetProcessHeap(), 0, This
);
473 HeapFree(GetProcessHeap(), 0, data
);
474 return E_OUTOFMEMORY
;
476 if (bits
) memcpy(data
, bits
, datasize
);
478 This
->IWICBitmap_iface
.lpVtbl
= &BitmapImpl_Vtbl
;
480 This
->palette
= NULL
;
481 This
->palette_set
= 0;
484 This
->width
= uiWidth
;
485 This
->height
= uiHeight
;
486 This
->stride
= stride
;
488 memcpy(&This
->pixelformat
, pixelFormat
, sizeof(GUID
));
489 This
->dpix
= This
->dpiy
= 0.0;
490 InitializeCriticalSection(&This
->cs
);
491 This
->cs
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": BitmapImpl.lock");
493 *ppIBitmap
= &This
->IWICBitmap_iface
;