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
19 #include "wincodecs_private.h"
21 typedef struct BitmapImpl
{
22 IWICBitmap IWICBitmap_iface
;
26 LONG lock
; /* 0 if not locked, -1 if locked for writing, count if locked for reading */
31 WICPixelFormatGUID pixelformat
;
36 typedef struct BitmapLockImpl
{
37 IWICBitmapLock IWICBitmapLock_iface
;
44 static inline BitmapImpl
*impl_from_IWICBitmap(IWICBitmap
*iface
)
46 return CONTAINING_RECORD(iface
, BitmapImpl
, IWICBitmap_iface
);
49 static inline BitmapLockImpl
*impl_from_IWICBitmapLock(IWICBitmapLock
*iface
)
51 return CONTAINING_RECORD(iface
, BitmapLockImpl
, IWICBitmapLock_iface
);
54 static BOOL
BitmapImpl_AcquireLock(BitmapImpl
*This
, int write
)
58 return 0 == InterlockedCompareExchange(&This
->lock
, -1, 0);
64 LONG prev_val
= This
->lock
;
67 if (prev_val
== InterlockedCompareExchange(&This
->lock
, prev_val
+1, prev_val
))
73 static void BitmapImpl_ReleaseLock(BitmapImpl
*This
)
77 LONG prev_val
= This
->lock
, new_val
;
81 new_val
= prev_val
- 1;
82 if (prev_val
== InterlockedCompareExchange(&This
->lock
, new_val
, prev_val
))
88 static HRESULT WINAPI
BitmapLockImpl_QueryInterface(IWICBitmapLock
*iface
, REFIID iid
,
91 BitmapLockImpl
*This
= impl_from_IWICBitmapLock(iface
);
92 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
94 if (!ppv
) return E_INVALIDARG
;
96 if (IsEqualIID(&IID_IUnknown
, iid
) ||
97 IsEqualIID(&IID_IWICBitmapLock
, iid
))
99 *ppv
= &This
->IWICBitmapLock_iface
;
104 return E_NOINTERFACE
;
107 IUnknown_AddRef((IUnknown
*)*ppv
);
111 static ULONG WINAPI
BitmapLockImpl_AddRef(IWICBitmapLock
*iface
)
113 BitmapLockImpl
*This
= impl_from_IWICBitmapLock(iface
);
114 ULONG ref
= InterlockedIncrement(&This
->ref
);
116 TRACE("(%p) refcount=%u\n", iface
, ref
);
121 static ULONG WINAPI
BitmapLockImpl_Release(IWICBitmapLock
*iface
)
123 BitmapLockImpl
*This
= impl_from_IWICBitmapLock(iface
);
124 ULONG ref
= InterlockedDecrement(&This
->ref
);
126 TRACE("(%p) refcount=%u\n", iface
, ref
);
130 BitmapImpl_ReleaseLock(This
->parent
);
131 IWICBitmap_Release(&This
->parent
->IWICBitmap_iface
);
132 HeapFree(GetProcessHeap(), 0, This
);
138 static HRESULT WINAPI
BitmapLockImpl_GetSize(IWICBitmapLock
*iface
,
139 UINT
*puiWidth
, UINT
*puiHeight
)
141 BitmapLockImpl
*This
= impl_from_IWICBitmapLock(iface
);
142 TRACE("(%p,%p,%p)\n", iface
, puiWidth
, puiHeight
);
144 if (!puiWidth
|| !puiHeight
)
147 *puiWidth
= This
->width
;
148 *puiHeight
= This
->height
;
153 static HRESULT WINAPI
BitmapLockImpl_GetStride(IWICBitmapLock
*iface
,
156 BitmapLockImpl
*This
= impl_from_IWICBitmapLock(iface
);
157 TRACE("(%p,%p)\n", iface
, pcbStride
);
162 *pcbStride
= This
->parent
->stride
;
167 static HRESULT WINAPI
BitmapLockImpl_GetDataPointer(IWICBitmapLock
*iface
,
168 UINT
*pcbBufferSize
, BYTE
**ppbData
)
170 BitmapLockImpl
*This
= impl_from_IWICBitmapLock(iface
);
171 TRACE("(%p,%p,%p)\n", iface
, pcbBufferSize
, ppbData
);
173 if (!pcbBufferSize
|| !ppbData
)
176 *pcbBufferSize
= This
->parent
->stride
* (This
->height
- 1) +
177 ((This
->parent
->bpp
* This
->width
) + 7)/8;
178 *ppbData
= This
->data
;
183 static HRESULT WINAPI
BitmapLockImpl_GetPixelFormat(IWICBitmapLock
*iface
,
184 WICPixelFormatGUID
*pPixelFormat
)
186 BitmapLockImpl
*This
= impl_from_IWICBitmapLock(iface
);
187 TRACE("(%p,%p)\n", iface
, pPixelFormat
);
189 return IWICBitmap_GetPixelFormat(&This
->parent
->IWICBitmap_iface
, pPixelFormat
);
192 static const IWICBitmapLockVtbl BitmapLockImpl_Vtbl
= {
193 BitmapLockImpl_QueryInterface
,
194 BitmapLockImpl_AddRef
,
195 BitmapLockImpl_Release
,
196 BitmapLockImpl_GetSize
,
197 BitmapLockImpl_GetStride
,
198 BitmapLockImpl_GetDataPointer
,
199 BitmapLockImpl_GetPixelFormat
202 static HRESULT WINAPI
BitmapImpl_QueryInterface(IWICBitmap
*iface
, REFIID iid
,
205 BitmapImpl
*This
= impl_from_IWICBitmap(iface
);
206 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
208 if (!ppv
) return E_INVALIDARG
;
210 if (IsEqualIID(&IID_IUnknown
, iid
) ||
211 IsEqualIID(&IID_IWICBitmapSource
, iid
) ||
212 IsEqualIID(&IID_IWICBitmap
, iid
))
214 *ppv
= &This
->IWICBitmap_iface
;
219 return E_NOINTERFACE
;
222 IUnknown_AddRef((IUnknown
*)*ppv
);
226 static ULONG WINAPI
BitmapImpl_AddRef(IWICBitmap
*iface
)
228 BitmapImpl
*This
= impl_from_IWICBitmap(iface
);
229 ULONG ref
= InterlockedIncrement(&This
->ref
);
231 TRACE("(%p) refcount=%u\n", iface
, ref
);
236 static ULONG WINAPI
BitmapImpl_Release(IWICBitmap
*iface
)
238 BitmapImpl
*This
= impl_from_IWICBitmap(iface
);
239 ULONG ref
= InterlockedDecrement(&This
->ref
);
241 TRACE("(%p) refcount=%u\n", iface
, ref
);
245 if (This
->palette
) IWICPalette_Release(This
->palette
);
246 This
->cs
.DebugInfo
->Spare
[0] = 0;
247 DeleteCriticalSection(&This
->cs
);
248 HeapFree(GetProcessHeap(), 0, This
->data
);
249 HeapFree(GetProcessHeap(), 0, This
);
255 static HRESULT WINAPI
BitmapImpl_GetSize(IWICBitmap
*iface
,
256 UINT
*puiWidth
, UINT
*puiHeight
)
258 BitmapImpl
*This
= impl_from_IWICBitmap(iface
);
259 TRACE("(%p,%p,%p)\n", iface
, puiWidth
, puiHeight
);
261 if (!puiWidth
|| !puiHeight
)
264 *puiWidth
= This
->width
;
265 *puiHeight
= This
->height
;
270 static HRESULT WINAPI
BitmapImpl_GetPixelFormat(IWICBitmap
*iface
,
271 WICPixelFormatGUID
*pPixelFormat
)
273 BitmapImpl
*This
= impl_from_IWICBitmap(iface
);
274 TRACE("(%p,%p)\n", iface
, pPixelFormat
);
279 memcpy(pPixelFormat
, &This
->pixelformat
, sizeof(GUID
));
284 static HRESULT WINAPI
BitmapImpl_GetResolution(IWICBitmap
*iface
,
285 double *pDpiX
, double *pDpiY
)
287 BitmapImpl
*This
= impl_from_IWICBitmap(iface
);
288 TRACE("(%p,%p,%p)\n", iface
, pDpiX
, pDpiY
);
290 if (!pDpiX
|| !pDpiY
)
293 EnterCriticalSection(&This
->cs
);
296 LeaveCriticalSection(&This
->cs
);
301 static HRESULT WINAPI
BitmapImpl_CopyPalette(IWICBitmap
*iface
,
302 IWICPalette
*pIPalette
)
304 BitmapImpl
*This
= impl_from_IWICBitmap(iface
);
305 TRACE("(%p,%p)\n", iface
, pIPalette
);
307 if (!This
->palette_set
)
308 return WINCODEC_ERR_PALETTEUNAVAILABLE
;
310 return IWICPalette_InitializeFromPalette(pIPalette
, This
->palette
);
313 static HRESULT WINAPI
BitmapImpl_CopyPixels(IWICBitmap
*iface
,
314 const WICRect
*prc
, UINT cbStride
, UINT cbBufferSize
, BYTE
*pbBuffer
)
316 BitmapImpl
*This
= impl_from_IWICBitmap(iface
);
317 TRACE("(%p,%p,%u,%u,%p)\n", iface
, prc
, cbStride
, cbBufferSize
, pbBuffer
);
319 return copy_pixels(This
->bpp
, This
->data
, This
->width
, This
->height
,
320 This
->stride
, prc
, cbStride
, cbBufferSize
, pbBuffer
);
323 static HRESULT WINAPI
BitmapImpl_Lock(IWICBitmap
*iface
, const WICRect
*prcLock
,
324 DWORD flags
, IWICBitmapLock
**ppILock
)
326 BitmapImpl
*This
= impl_from_IWICBitmap(iface
);
327 BitmapLockImpl
*result
;
330 TRACE("(%p,%p,%x,%p)\n", iface
, prcLock
, flags
, ppILock
);
332 if (!(flags
& (WICBitmapLockRead
|WICBitmapLockWrite
)) || !ppILock
)
338 rc
.Width
= This
->width
;
339 rc
.Height
= This
->height
;
342 else if (prcLock
->X
>= This
->width
|| prcLock
->Y
>= This
->height
||
343 prcLock
->X
+ prcLock
->Width
> This
->width
||
344 prcLock
->Y
+ prcLock
->Height
> This
->height
||
345 prcLock
->Width
<= 0 || prcLock
->Height
<= 0)
347 else if (((prcLock
->X
* This
->bpp
) % 8) != 0)
349 FIXME("Cannot lock at an X coordinate not at a full byte\n");
353 result
= HeapAlloc(GetProcessHeap(), 0, sizeof(BitmapLockImpl
));
355 return E_OUTOFMEMORY
;
357 if (!BitmapImpl_AcquireLock(This
, flags
& WICBitmapLockWrite
))
359 HeapFree(GetProcessHeap(), 0, result
);
360 return WINCODEC_ERR_ALREADYLOCKED
;
363 result
->IWICBitmapLock_iface
.lpVtbl
= &BitmapLockImpl_Vtbl
;
365 result
->parent
= This
;
366 result
->width
= prcLock
->Width
;
367 result
->height
= prcLock
->Height
;
368 result
->data
= This
->data
+ This
->stride
* prcLock
->Y
+
369 (This
->bpp
* prcLock
->X
)/8;
371 IWICBitmap_AddRef(&This
->IWICBitmap_iface
);
372 *ppILock
= &result
->IWICBitmapLock_iface
;
377 static HRESULT WINAPI
BitmapImpl_SetPalette(IWICBitmap
*iface
, IWICPalette
*pIPalette
)
379 BitmapImpl
*This
= impl_from_IWICBitmap(iface
);
382 TRACE("(%p,%p)\n", iface
, pIPalette
);
386 IWICPalette
*new_palette
;
387 hr
= PaletteImpl_Create(&new_palette
);
389 if (FAILED(hr
)) return hr
;
391 if (InterlockedCompareExchangePointer((void**)&This
->palette
, new_palette
, NULL
))
393 /* someone beat us to it */
394 IWICPalette_Release(new_palette
);
398 hr
= IWICPalette_InitializeFromPalette(This
->palette
, pIPalette
);
401 This
->palette_set
= 1;
406 static HRESULT WINAPI
BitmapImpl_SetResolution(IWICBitmap
*iface
,
407 double dpiX
, double dpiY
)
409 BitmapImpl
*This
= impl_from_IWICBitmap(iface
);
410 TRACE("(%p,%f,%f)\n", iface
, dpiX
, dpiY
);
412 EnterCriticalSection(&This
->cs
);
415 LeaveCriticalSection(&This
->cs
);
420 static const IWICBitmapVtbl BitmapImpl_Vtbl
= {
421 BitmapImpl_QueryInterface
,
425 BitmapImpl_GetPixelFormat
,
426 BitmapImpl_GetResolution
,
427 BitmapImpl_CopyPalette
,
428 BitmapImpl_CopyPixels
,
430 BitmapImpl_SetPalette
,
431 BitmapImpl_SetResolution
434 HRESULT
BitmapImpl_Create(UINT uiWidth
, UINT uiHeight
,
435 UINT stride
, UINT datasize
, BYTE
*bits
,
436 REFWICPixelFormatGUID pixelFormat
, WICBitmapCreateCacheOption option
,
437 IWICBitmap
**ppIBitmap
)
444 hr
= get_pixelformat_bpp(pixelFormat
, &bpp
);
445 if (FAILED(hr
)) return hr
;
447 if (!stride
) stride
= (((bpp
*uiWidth
)+31)/32)*4;
448 if (!datasize
) datasize
= stride
* uiHeight
;
450 if (datasize
< stride
* uiHeight
) return WINCODEC_ERR_INSUFFICIENTBUFFER
;
451 if (stride
< ((bpp
*uiWidth
)+7)/8) return E_INVALIDARG
;
453 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(BitmapImpl
));
454 data
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, datasize
);
457 HeapFree(GetProcessHeap(), 0, This
);
458 HeapFree(GetProcessHeap(), 0, data
);
459 return E_OUTOFMEMORY
;
461 if (bits
) memcpy(data
, bits
, datasize
);
463 This
->IWICBitmap_iface
.lpVtbl
= &BitmapImpl_Vtbl
;
465 This
->palette
= NULL
;
466 This
->palette_set
= 0;
469 This
->width
= uiWidth
;
470 This
->height
= uiHeight
;
471 This
->stride
= stride
;
473 memcpy(&This
->pixelformat
, pixelFormat
, sizeof(GUID
));
474 This
->dpix
= This
->dpiy
= 0.0;
475 InitializeCriticalSection(&This
->cs
);
476 This
->cs
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": BitmapImpl.lock");
478 *ppIBitmap
= &This
->IWICBitmap_iface
;