1 /* 2 * Copyright 2012 Vincent Povirk for CodeWeavers 3 * 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. 8 * 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. 13 * 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 17 */ 18 19 #define WIN32_NO_STATUS 20 #define _INC_WINDOWS 21 #define COM_NO_WINDOWS_H 22 23 #include <config.h> 24 25 #include <stdarg.h> 26 27 #define COBJMACROS 28 29 #include <windef.h> 30 #include <winbase.h> 31 #include <objbase.h> 32 #include <wincodec.h> 33 34 #include "wincodecs_private.h" 35 36 #include <wine/debug.h> 37 38 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs); 39 40 typedef struct BitmapImpl { 41 IWICBitmap IWICBitmap_iface; 42 LONG ref; 43 IWICPalette *palette; 44 int palette_set; 45 LONG lock; /* 0 if not locked, -1 if locked for writing, count if locked for reading */ 46 BYTE *data; 47 UINT width, height; 48 UINT stride; 49 UINT bpp; 50 WICPixelFormatGUID pixelformat; 51 double dpix, dpiy; 52 CRITICAL_SECTION cs; 53 } BitmapImpl; 54 55 typedef struct BitmapLockImpl { 56 IWICBitmapLock IWICBitmapLock_iface; 57 LONG ref; 58 BitmapImpl *parent; 59 UINT width, height; 60 BYTE *data; 61 } BitmapLockImpl; 62 63 static inline BitmapImpl *impl_from_IWICBitmap(IWICBitmap *iface) 64 { 65 return CONTAINING_RECORD(iface, BitmapImpl, IWICBitmap_iface); 66 } 67 68 static inline BitmapLockImpl *impl_from_IWICBitmapLock(IWICBitmapLock *iface) 69 { 70 return CONTAINING_RECORD(iface, BitmapLockImpl, IWICBitmapLock_iface); 71 } 72 73 static BOOL BitmapImpl_AcquireLock(BitmapImpl *This, int write) 74 { 75 if (write) 76 { 77 return 0 == InterlockedCompareExchange(&This->lock, -1, 0); 78 } 79 else 80 { 81 while (1) 82 { 83 LONG prev_val = This->lock; 84 if (prev_val == -1) 85 return FALSE; 86 if (prev_val == InterlockedCompareExchange(&This->lock, prev_val+1, prev_val)) 87 return TRUE; 88 } 89 } 90 } 91 92 static void BitmapImpl_ReleaseLock(BitmapImpl *This) 93 { 94 while (1) 95 { 96 LONG prev_val = This->lock, new_val; 97 if (prev_val == -1) 98 new_val = 0; 99 else 100 new_val = prev_val - 1; 101 if (prev_val == InterlockedCompareExchange(&This->lock, new_val, prev_val)) 102 break; 103 } 104 } 105 106 107 static HRESULT WINAPI BitmapLockImpl_QueryInterface(IWICBitmapLock *iface, REFIID iid, 108 void **ppv) 109 { 110 BitmapLockImpl *This = impl_from_IWICBitmapLock(iface); 111 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); 112 113 if (!ppv) return E_INVALIDARG; 114 115 if (IsEqualIID(&IID_IUnknown, iid) || 116 IsEqualIID(&IID_IWICBitmapLock, iid)) 117 { 118 *ppv = &This->IWICBitmapLock_iface; 119 } 120 else 121 { 122 *ppv = NULL; 123 return E_NOINTERFACE; 124 } 125 126 IUnknown_AddRef((IUnknown*)*ppv); 127 return S_OK; 128 } 129 130 static ULONG WINAPI BitmapLockImpl_AddRef(IWICBitmapLock *iface) 131 { 132 BitmapLockImpl *This = impl_from_IWICBitmapLock(iface); 133 ULONG ref = InterlockedIncrement(&This->ref); 134 135 TRACE("(%p) refcount=%u\n", iface, ref); 136 137 return ref; 138 } 139 140 static ULONG WINAPI BitmapLockImpl_Release(IWICBitmapLock *iface) 141 { 142 BitmapLockImpl *This = impl_from_IWICBitmapLock(iface); 143 ULONG ref = InterlockedDecrement(&This->ref); 144 145 TRACE("(%p) refcount=%u\n", iface, ref); 146 147 if (ref == 0) 148 { 149 BitmapImpl_ReleaseLock(This->parent); 150 IWICBitmap_Release(&This->parent->IWICBitmap_iface); 151 HeapFree(GetProcessHeap(), 0, This); 152 } 153 154 return ref; 155 } 156 157 static HRESULT WINAPI BitmapLockImpl_GetSize(IWICBitmapLock *iface, 158 UINT *puiWidth, UINT *puiHeight) 159 { 160 BitmapLockImpl *This = impl_from_IWICBitmapLock(iface); 161 TRACE("(%p,%p,%p)\n", iface, puiWidth, puiHeight); 162 163 if (!puiWidth || !puiHeight) 164 return E_INVALIDARG; 165 166 *puiWidth = This->width; 167 *puiHeight = This->height; 168 169 return S_OK; 170 } 171 172 static HRESULT WINAPI BitmapLockImpl_GetStride(IWICBitmapLock *iface, 173 UINT *pcbStride) 174 { 175 BitmapLockImpl *This = impl_from_IWICBitmapLock(iface); 176 TRACE("(%p,%p)\n", iface, pcbStride); 177 178 if (!pcbStride) 179 return E_INVALIDARG; 180 181 *pcbStride = This->parent->stride; 182 183 return S_OK; 184 } 185 186 static HRESULT WINAPI BitmapLockImpl_GetDataPointer(IWICBitmapLock *iface, 187 UINT *pcbBufferSize, BYTE **ppbData) 188 { 189 BitmapLockImpl *This = impl_from_IWICBitmapLock(iface); 190 TRACE("(%p,%p,%p)\n", iface, pcbBufferSize, ppbData); 191 192 if (!pcbBufferSize || !ppbData) 193 return E_INVALIDARG; 194 195 *pcbBufferSize = This->parent->stride * (This->height - 1) + 196 ((This->parent->bpp * This->width) + 7)/8; 197 *ppbData = This->data; 198 199 return S_OK; 200 } 201 202 static HRESULT WINAPI BitmapLockImpl_GetPixelFormat(IWICBitmapLock *iface, 203 WICPixelFormatGUID *pPixelFormat) 204 { 205 BitmapLockImpl *This = impl_from_IWICBitmapLock(iface); 206 TRACE("(%p,%p)\n", iface, pPixelFormat); 207 208 return IWICBitmap_GetPixelFormat(&This->parent->IWICBitmap_iface, pPixelFormat); 209 } 210 211 static const IWICBitmapLockVtbl BitmapLockImpl_Vtbl = { 212 BitmapLockImpl_QueryInterface, 213 BitmapLockImpl_AddRef, 214 BitmapLockImpl_Release, 215 BitmapLockImpl_GetSize, 216 BitmapLockImpl_GetStride, 217 BitmapLockImpl_GetDataPointer, 218 BitmapLockImpl_GetPixelFormat 219 }; 220 221 static HRESULT WINAPI BitmapImpl_QueryInterface(IWICBitmap *iface, REFIID iid, 222 void **ppv) 223 { 224 BitmapImpl *This = impl_from_IWICBitmap(iface); 225 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); 226 227 if (!ppv) return E_INVALIDARG; 228 229 if (IsEqualIID(&IID_IUnknown, iid) || 230 IsEqualIID(&IID_IWICBitmapSource, iid) || 231 IsEqualIID(&IID_IWICBitmap, iid)) 232 { 233 *ppv = &This->IWICBitmap_iface; 234 } 235 else 236 { 237 *ppv = NULL; 238 return E_NOINTERFACE; 239 } 240 241 IUnknown_AddRef((IUnknown*)*ppv); 242 return S_OK; 243 } 244 245 static ULONG WINAPI BitmapImpl_AddRef(IWICBitmap *iface) 246 { 247 BitmapImpl *This = impl_from_IWICBitmap(iface); 248 ULONG ref = InterlockedIncrement(&This->ref); 249 250 TRACE("(%p) refcount=%u\n", iface, ref); 251 252 return ref; 253 } 254 255 static ULONG WINAPI BitmapImpl_Release(IWICBitmap *iface) 256 { 257 BitmapImpl *This = impl_from_IWICBitmap(iface); 258 ULONG ref = InterlockedDecrement(&This->ref); 259 260 TRACE("(%p) refcount=%u\n", iface, ref); 261 262 if (ref == 0) 263 { 264 if (This->palette) IWICPalette_Release(This->palette); 265 This->cs.DebugInfo->Spare[0] = 0; 266 DeleteCriticalSection(&This->cs); 267 HeapFree(GetProcessHeap(), 0, This->data); 268 HeapFree(GetProcessHeap(), 0, This); 269 } 270 271 return ref; 272 } 273 274 static HRESULT WINAPI BitmapImpl_GetSize(IWICBitmap *iface, 275 UINT *puiWidth, UINT *puiHeight) 276 { 277 BitmapImpl *This = impl_from_IWICBitmap(iface); 278 TRACE("(%p,%p,%p)\n", iface, puiWidth, puiHeight); 279 280 if (!puiWidth || !puiHeight) 281 return E_INVALIDARG; 282 283 *puiWidth = This->width; 284 *puiHeight = This->height; 285 286 return S_OK; 287 } 288 289 static HRESULT WINAPI BitmapImpl_GetPixelFormat(IWICBitmap *iface, 290 WICPixelFormatGUID *pPixelFormat) 291 { 292 BitmapImpl *This = impl_from_IWICBitmap(iface); 293 TRACE("(%p,%p)\n", iface, pPixelFormat); 294 295 if (!pPixelFormat) 296 return E_INVALIDARG; 297 298 memcpy(pPixelFormat, &This->pixelformat, sizeof(GUID)); 299 300 return S_OK; 301 } 302 303 static HRESULT WINAPI BitmapImpl_GetResolution(IWICBitmap *iface, 304 double *pDpiX, double *pDpiY) 305 { 306 BitmapImpl *This = impl_from_IWICBitmap(iface); 307 TRACE("(%p,%p,%p)\n", iface, pDpiX, pDpiY); 308 309 if (!pDpiX || !pDpiY) 310 return E_INVALIDARG; 311 312 EnterCriticalSection(&This->cs); 313 *pDpiX = This->dpix; 314 *pDpiY = This->dpiy; 315 LeaveCriticalSection(&This->cs); 316 317 return S_OK; 318 } 319 320 static HRESULT WINAPI BitmapImpl_CopyPalette(IWICBitmap *iface, 321 IWICPalette *pIPalette) 322 { 323 BitmapImpl *This = impl_from_IWICBitmap(iface); 324 TRACE("(%p,%p)\n", iface, pIPalette); 325 326 if (!This->palette_set) 327 return WINCODEC_ERR_PALETTEUNAVAILABLE; 328 329 return IWICPalette_InitializeFromPalette(pIPalette, This->palette); 330 } 331 332 static HRESULT WINAPI BitmapImpl_CopyPixels(IWICBitmap *iface, 333 const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer) 334 { 335 BitmapImpl *This = impl_from_IWICBitmap(iface); 336 TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer); 337 338 return copy_pixels(This->bpp, This->data, This->width, This->height, 339 This->stride, prc, cbStride, cbBufferSize, pbBuffer); 340 } 341 342 static HRESULT WINAPI BitmapImpl_Lock(IWICBitmap *iface, const WICRect *prcLock, 343 DWORD flags, IWICBitmapLock **ppILock) 344 { 345 BitmapImpl *This = impl_from_IWICBitmap(iface); 346 BitmapLockImpl *result; 347 WICRect rc; 348 349 TRACE("(%p,%p,%x,%p)\n", iface, prcLock, flags, ppILock); 350 351 if (!(flags & (WICBitmapLockRead|WICBitmapLockWrite)) || !ppILock) 352 return E_INVALIDARG; 353 354 if (!prcLock) 355 { 356 rc.X = rc.Y = 0; 357 rc.Width = This->width; 358 rc.Height = This->height; 359 prcLock = &rc; 360 } 361 else if (prcLock->X >= This->width || prcLock->Y >= This->height || 362 prcLock->X + prcLock->Width > This->width || 363 prcLock->Y + prcLock->Height > This->height || 364 prcLock->Width <= 0 || prcLock->Height <= 0) 365 return E_INVALIDARG; 366 else if (((prcLock->X * This->bpp) % 8) != 0) 367 { 368 FIXME("Cannot lock at an X coordinate not at a full byte\n"); 369 return E_FAIL; 370 } 371 372 result = HeapAlloc(GetProcessHeap(), 0, sizeof(BitmapLockImpl)); 373 if (!result) 374 return E_OUTOFMEMORY; 375 376 if (!BitmapImpl_AcquireLock(This, flags & WICBitmapLockWrite)) 377 { 378 HeapFree(GetProcessHeap(), 0, result); 379 return WINCODEC_ERR_ALREADYLOCKED; 380 } 381 382 result->IWICBitmapLock_iface.lpVtbl = &BitmapLockImpl_Vtbl; 383 result->ref = 1; 384 result->parent = This; 385 result->width = prcLock->Width; 386 result->height = prcLock->Height; 387 result->data = This->data + This->stride * prcLock->Y + 388 (This->bpp * prcLock->X)/8; 389 390 IWICBitmap_AddRef(&This->IWICBitmap_iface); 391 *ppILock = &result->IWICBitmapLock_iface; 392 393 return S_OK; 394 } 395 396 static HRESULT WINAPI BitmapImpl_SetPalette(IWICBitmap *iface, IWICPalette *pIPalette) 397 { 398 BitmapImpl *This = impl_from_IWICBitmap(iface); 399 HRESULT hr; 400 401 TRACE("(%p,%p)\n", iface, pIPalette); 402 403 if (!This->palette) 404 { 405 IWICPalette *new_palette; 406 hr = PaletteImpl_Create(&new_palette); 407 408 if (FAILED(hr)) return hr; 409 410 if (InterlockedCompareExchangePointer((void**)&This->palette, new_palette, NULL)) 411 { 412 /* someone beat us to it */ 413 IWICPalette_Release(new_palette); 414 } 415 } 416 417 hr = IWICPalette_InitializeFromPalette(This->palette, pIPalette); 418 419 if (SUCCEEDED(hr)) 420 This->palette_set = 1; 421 422 return S_OK; 423 } 424 425 static HRESULT WINAPI BitmapImpl_SetResolution(IWICBitmap *iface, 426 double dpiX, double dpiY) 427 { 428 BitmapImpl *This = impl_from_IWICBitmap(iface); 429 TRACE("(%p,%f,%f)\n", iface, dpiX, dpiY); 430 431 EnterCriticalSection(&This->cs); 432 This->dpix = dpiX; 433 This->dpiy = dpiY; 434 LeaveCriticalSection(&This->cs); 435 436 return S_OK; 437 } 438 439 static const IWICBitmapVtbl BitmapImpl_Vtbl = { 440 BitmapImpl_QueryInterface, 441 BitmapImpl_AddRef, 442 BitmapImpl_Release, 443 BitmapImpl_GetSize, 444 BitmapImpl_GetPixelFormat, 445 BitmapImpl_GetResolution, 446 BitmapImpl_CopyPalette, 447 BitmapImpl_CopyPixels, 448 BitmapImpl_Lock, 449 BitmapImpl_SetPalette, 450 BitmapImpl_SetResolution 451 }; 452 453 HRESULT BitmapImpl_Create(UINT uiWidth, UINT uiHeight, 454 UINT stride, UINT datasize, BYTE *bits, 455 REFWICPixelFormatGUID pixelFormat, WICBitmapCreateCacheOption option, 456 IWICBitmap **ppIBitmap) 457 { 458 HRESULT hr; 459 BitmapImpl *This; 460 BYTE *data; 461 UINT bpp; 462 463 hr = get_pixelformat_bpp(pixelFormat, &bpp); 464 if (FAILED(hr)) return hr; 465 466 if (!stride) stride = (((bpp*uiWidth)+31)/32)*4; 467 if (!datasize) datasize = stride * uiHeight; 468 469 if (datasize < stride * uiHeight) return WINCODEC_ERR_INSUFFICIENTBUFFER; 470 if (stride < ((bpp*uiWidth)+7)/8) return E_INVALIDARG; 471 472 This = HeapAlloc(GetProcessHeap(), 0, sizeof(BitmapImpl)); 473 data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, datasize); 474 if (!This || !data) 475 { 476 HeapFree(GetProcessHeap(), 0, This); 477 HeapFree(GetProcessHeap(), 0, data); 478 return E_OUTOFMEMORY; 479 } 480 if (bits) memcpy(data, bits, datasize); 481 482 This->IWICBitmap_iface.lpVtbl = &BitmapImpl_Vtbl; 483 This->ref = 1; 484 This->palette = NULL; 485 This->palette_set = 0; 486 This->lock = 0; 487 This->data = data; 488 This->width = uiWidth; 489 This->height = uiHeight; 490 This->stride = stride; 491 This->bpp = bpp; 492 memcpy(&This->pixelformat, pixelFormat, sizeof(GUID)); 493 This->dpix = This->dpiy = 0.0; 494 InitializeCriticalSection(&This->cs); 495 This->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": BitmapImpl.lock"); 496 497 *ppIBitmap = &This->IWICBitmap_iface; 498 499 return S_OK; 500 } 501