[WINDOWSCODECS] Sync with Wine Staging 4.0. CORE-15682
[reactos.git] / dll / win32 / windowscodecs / bitmap.c
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 #include "config.h"
20
21 #include <stdarg.h>
22
23 #define COBJMACROS
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "objbase.h"
28
29 #include "wincodecs_private.h"
30
31 #include "wine/debug.h"
32
33 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
34
35 /* WARNING: .NET Media Integration Layer (MIL) directly dereferences
36 * BitmapImpl members and depends on its exact layout.
37 */
38 typedef struct BitmapImpl {
39 IMILUnknown1 IMILUnknown1_iface;
40 LONG ref;
41 IMILBitmapSource IMILBitmapSource_iface;
42 IWICBitmap IWICBitmap_iface;
43 IMILUnknown2 IMILUnknown2_iface;
44 IWICPalette *palette;
45 int palette_set;
46 LONG lock; /* 0 if not locked, -1 if locked for writing, count if locked for reading */
47 BYTE *data;
48 void *view; /* used if data is a section created by an application */
49 UINT offset; /* offset into view */
50 UINT width, height;
51 UINT stride;
52 UINT bpp;
53 WICPixelFormatGUID pixelformat;
54 double dpix, dpiy;
55 CRITICAL_SECTION cs;
56 } BitmapImpl;
57
58 typedef struct BitmapLockImpl {
59 IWICBitmapLock IWICBitmapLock_iface;
60 LONG ref;
61 BitmapImpl *parent;
62 UINT width, height;
63 BYTE *data;
64 } BitmapLockImpl;
65
66 static inline BitmapImpl *impl_from_IWICBitmap(IWICBitmap *iface)
67 {
68 return CONTAINING_RECORD(iface, BitmapImpl, IWICBitmap_iface);
69 }
70
71 static inline BitmapImpl *impl_from_IMILBitmapSource(IMILBitmapSource *iface)
72 {
73 return CONTAINING_RECORD(iface, BitmapImpl, IMILBitmapSource_iface);
74 }
75
76 static inline BitmapImpl *impl_from_IMILUnknown1(IMILUnknown1 *iface)
77 {
78 return CONTAINING_RECORD(iface, BitmapImpl, IMILUnknown1_iface);
79 }
80
81 static inline BitmapImpl *impl_from_IMILUnknown2(IMILUnknown2 *iface)
82 {
83 return CONTAINING_RECORD(iface, BitmapImpl, IMILUnknown2_iface);
84 }
85
86 static inline BitmapLockImpl *impl_from_IWICBitmapLock(IWICBitmapLock *iface)
87 {
88 return CONTAINING_RECORD(iface, BitmapLockImpl, IWICBitmapLock_iface);
89 }
90
91 static BOOL BitmapImpl_AcquireLock(BitmapImpl *This, int write)
92 {
93 if (write)
94 {
95 return 0 == InterlockedCompareExchange(&This->lock, -1, 0);
96 }
97 else
98 {
99 while (1)
100 {
101 LONG prev_val = This->lock;
102 if (prev_val == -1)
103 return FALSE;
104 if (prev_val == InterlockedCompareExchange(&This->lock, prev_val+1, prev_val))
105 return TRUE;
106 }
107 }
108 }
109
110 static void BitmapImpl_ReleaseLock(BitmapImpl *This)
111 {
112 while (1)
113 {
114 LONG prev_val = This->lock, new_val;
115 if (prev_val == -1)
116 new_val = 0;
117 else
118 new_val = prev_val - 1;
119 if (prev_val == InterlockedCompareExchange(&This->lock, new_val, prev_val))
120 break;
121 }
122 }
123
124
125 static HRESULT WINAPI BitmapLockImpl_QueryInterface(IWICBitmapLock *iface, REFIID iid,
126 void **ppv)
127 {
128 BitmapLockImpl *This = impl_from_IWICBitmapLock(iface);
129 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
130
131 if (!ppv) return E_INVALIDARG;
132
133 if (IsEqualIID(&IID_IUnknown, iid) ||
134 IsEqualIID(&IID_IWICBitmapLock, iid))
135 {
136 *ppv = &This->IWICBitmapLock_iface;
137 }
138 else
139 {
140 FIXME("unknown interface %s\n", debugstr_guid(iid));
141 *ppv = NULL;
142 return E_NOINTERFACE;
143 }
144
145 IUnknown_AddRef((IUnknown*)*ppv);
146 return S_OK;
147 }
148
149 static ULONG WINAPI BitmapLockImpl_AddRef(IWICBitmapLock *iface)
150 {
151 BitmapLockImpl *This = impl_from_IWICBitmapLock(iface);
152 ULONG ref = InterlockedIncrement(&This->ref);
153
154 TRACE("(%p) refcount=%u\n", iface, ref);
155
156 return ref;
157 }
158
159 static ULONG WINAPI BitmapLockImpl_Release(IWICBitmapLock *iface)
160 {
161 BitmapLockImpl *This = impl_from_IWICBitmapLock(iface);
162 ULONG ref = InterlockedDecrement(&This->ref);
163
164 TRACE("(%p) refcount=%u\n", iface, ref);
165
166 if (ref == 0)
167 {
168 BitmapImpl_ReleaseLock(This->parent);
169 IWICBitmap_Release(&This->parent->IWICBitmap_iface);
170 HeapFree(GetProcessHeap(), 0, This);
171 }
172
173 return ref;
174 }
175
176 static HRESULT WINAPI BitmapLockImpl_GetSize(IWICBitmapLock *iface,
177 UINT *puiWidth, UINT *puiHeight)
178 {
179 BitmapLockImpl *This = impl_from_IWICBitmapLock(iface);
180 TRACE("(%p,%p,%p)\n", iface, puiWidth, puiHeight);
181
182 if (!puiWidth || !puiHeight)
183 return E_INVALIDARG;
184
185 *puiWidth = This->width;
186 *puiHeight = This->height;
187
188 return S_OK;
189 }
190
191 static HRESULT WINAPI BitmapLockImpl_GetStride(IWICBitmapLock *iface,
192 UINT *pcbStride)
193 {
194 BitmapLockImpl *This = impl_from_IWICBitmapLock(iface);
195 TRACE("(%p,%p)\n", iface, pcbStride);
196
197 if (!pcbStride)
198 return E_INVALIDARG;
199
200 *pcbStride = This->parent->stride;
201
202 return S_OK;
203 }
204
205 static HRESULT WINAPI BitmapLockImpl_GetDataPointer(IWICBitmapLock *iface,
206 UINT *pcbBufferSize, BYTE **ppbData)
207 {
208 BitmapLockImpl *This = impl_from_IWICBitmapLock(iface);
209 TRACE("(%p,%p,%p)\n", iface, pcbBufferSize, ppbData);
210
211 if (!pcbBufferSize || !ppbData)
212 return E_INVALIDARG;
213
214 *pcbBufferSize = This->parent->stride * (This->height - 1) +
215 ((This->parent->bpp * This->width) + 7)/8;
216 *ppbData = This->data;
217
218 return S_OK;
219 }
220
221 static HRESULT WINAPI BitmapLockImpl_GetPixelFormat(IWICBitmapLock *iface,
222 WICPixelFormatGUID *pPixelFormat)
223 {
224 BitmapLockImpl *This = impl_from_IWICBitmapLock(iface);
225 TRACE("(%p,%p)\n", iface, pPixelFormat);
226
227 return IWICBitmap_GetPixelFormat(&This->parent->IWICBitmap_iface, pPixelFormat);
228 }
229
230 static const IWICBitmapLockVtbl BitmapLockImpl_Vtbl = {
231 BitmapLockImpl_QueryInterface,
232 BitmapLockImpl_AddRef,
233 BitmapLockImpl_Release,
234 BitmapLockImpl_GetSize,
235 BitmapLockImpl_GetStride,
236 BitmapLockImpl_GetDataPointer,
237 BitmapLockImpl_GetPixelFormat
238 };
239
240 static HRESULT WINAPI BitmapImpl_QueryInterface(IWICBitmap *iface, REFIID iid,
241 void **ppv)
242 {
243 BitmapImpl *This = impl_from_IWICBitmap(iface);
244 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
245
246 if (!ppv) return E_INVALIDARG;
247
248 if (IsEqualIID(&IID_IUnknown, iid) ||
249 IsEqualIID(&IID_IWICBitmapSource, iid) ||
250 IsEqualIID(&IID_IWICBitmap, iid))
251 {
252 *ppv = &This->IWICBitmap_iface;
253 }
254 else if (IsEqualIID(&IID_IMILBitmap, iid) ||
255 IsEqualIID(&IID_IMILBitmapSource, iid))
256 {
257 *ppv = &This->IMILBitmapSource_iface;
258 }
259 else
260 {
261 FIXME("unknown interface %s\n", debugstr_guid(iid));
262 *ppv = NULL;
263 return E_NOINTERFACE;
264 }
265
266 IUnknown_AddRef((IUnknown*)*ppv);
267 return S_OK;
268 }
269
270 static ULONG WINAPI BitmapImpl_AddRef(IWICBitmap *iface)
271 {
272 BitmapImpl *This = impl_from_IWICBitmap(iface);
273 ULONG ref = InterlockedIncrement(&This->ref);
274
275 TRACE("(%p) refcount=%u\n", iface, ref);
276
277 return ref;
278 }
279
280 static ULONG WINAPI BitmapImpl_Release(IWICBitmap *iface)
281 {
282 BitmapImpl *This = impl_from_IWICBitmap(iface);
283 ULONG ref = InterlockedDecrement(&This->ref);
284
285 TRACE("(%p) refcount=%u\n", iface, ref);
286
287 if (ref == 0)
288 {
289 if (This->palette) IWICPalette_Release(This->palette);
290 This->cs.DebugInfo->Spare[0] = 0;
291 DeleteCriticalSection(&This->cs);
292 if (This->view)
293 UnmapViewOfFile(This->view);
294 else
295 HeapFree(GetProcessHeap(), 0, This->data);
296 HeapFree(GetProcessHeap(), 0, This);
297 }
298
299 return ref;
300 }
301
302 static HRESULT WINAPI BitmapImpl_GetSize(IWICBitmap *iface,
303 UINT *puiWidth, UINT *puiHeight)
304 {
305 BitmapImpl *This = impl_from_IWICBitmap(iface);
306 TRACE("(%p,%p,%p)\n", iface, puiWidth, puiHeight);
307
308 if (!puiWidth || !puiHeight)
309 return E_INVALIDARG;
310
311 *puiWidth = This->width;
312 *puiHeight = This->height;
313
314 return S_OK;
315 }
316
317 static HRESULT WINAPI BitmapImpl_GetPixelFormat(IWICBitmap *iface,
318 WICPixelFormatGUID *pPixelFormat)
319 {
320 BitmapImpl *This = impl_from_IWICBitmap(iface);
321 TRACE("(%p,%p)\n", iface, pPixelFormat);
322
323 if (!pPixelFormat)
324 return E_INVALIDARG;
325
326 memcpy(pPixelFormat, &This->pixelformat, sizeof(GUID));
327
328 return S_OK;
329 }
330
331 static HRESULT WINAPI BitmapImpl_GetResolution(IWICBitmap *iface,
332 double *pDpiX, double *pDpiY)
333 {
334 BitmapImpl *This = impl_from_IWICBitmap(iface);
335 TRACE("(%p,%p,%p)\n", iface, pDpiX, pDpiY);
336
337 if (!pDpiX || !pDpiY)
338 return E_INVALIDARG;
339
340 EnterCriticalSection(&This->cs);
341 *pDpiX = This->dpix;
342 *pDpiY = This->dpiy;
343 LeaveCriticalSection(&This->cs);
344
345 return S_OK;
346 }
347
348 static HRESULT WINAPI BitmapImpl_CopyPalette(IWICBitmap *iface,
349 IWICPalette *pIPalette)
350 {
351 BitmapImpl *This = impl_from_IWICBitmap(iface);
352 TRACE("(%p,%p)\n", iface, pIPalette);
353
354 if (!This->palette_set)
355 return WINCODEC_ERR_PALETTEUNAVAILABLE;
356
357 return IWICPalette_InitializeFromPalette(pIPalette, This->palette);
358 }
359
360 static HRESULT WINAPI BitmapImpl_CopyPixels(IWICBitmap *iface,
361 const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
362 {
363 BitmapImpl *This = impl_from_IWICBitmap(iface);
364 TRACE("(%p,%s,%u,%u,%p)\n", iface, debug_wic_rect(prc), cbStride, cbBufferSize, pbBuffer);
365
366 return copy_pixels(This->bpp, This->data, This->width, This->height,
367 This->stride, prc, cbStride, cbBufferSize, pbBuffer);
368 }
369
370 static HRESULT WINAPI BitmapImpl_Lock(IWICBitmap *iface, const WICRect *prcLock,
371 DWORD flags, IWICBitmapLock **ppILock)
372 {
373 BitmapImpl *This = impl_from_IWICBitmap(iface);
374 BitmapLockImpl *result;
375 WICRect rc;
376
377 TRACE("(%p,%s,%x,%p)\n", iface, debug_wic_rect(prcLock), flags, ppILock);
378
379 if (!(flags & (WICBitmapLockRead|WICBitmapLockWrite)) || !ppILock)
380 return E_INVALIDARG;
381
382 if (!prcLock)
383 {
384 rc.X = rc.Y = 0;
385 rc.Width = This->width;
386 rc.Height = This->height;
387 prcLock = &rc;
388 }
389 else if (prcLock->X >= This->width || prcLock->Y >= This->height ||
390 prcLock->X + prcLock->Width > This->width ||
391 prcLock->Y + prcLock->Height > This->height ||
392 prcLock->Width <= 0 || prcLock->Height <= 0)
393 return E_INVALIDARG;
394 else if (((prcLock->X * This->bpp) % 8) != 0)
395 {
396 FIXME("Cannot lock at an X coordinate not at a full byte\n");
397 return E_FAIL;
398 }
399
400 result = HeapAlloc(GetProcessHeap(), 0, sizeof(BitmapLockImpl));
401 if (!result)
402 return E_OUTOFMEMORY;
403
404 if (!BitmapImpl_AcquireLock(This, flags & WICBitmapLockWrite))
405 {
406 HeapFree(GetProcessHeap(), 0, result);
407 return WINCODEC_ERR_ALREADYLOCKED;
408 }
409
410 result->IWICBitmapLock_iface.lpVtbl = &BitmapLockImpl_Vtbl;
411 result->ref = 1;
412 result->parent = This;
413 result->width = prcLock->Width;
414 result->height = prcLock->Height;
415 result->data = This->data + This->stride * prcLock->Y +
416 (This->bpp * prcLock->X)/8;
417
418 IWICBitmap_AddRef(&This->IWICBitmap_iface);
419 *ppILock = &result->IWICBitmapLock_iface;
420
421 return S_OK;
422 }
423
424 static HRESULT WINAPI BitmapImpl_SetPalette(IWICBitmap *iface, IWICPalette *pIPalette)
425 {
426 BitmapImpl *This = impl_from_IWICBitmap(iface);
427 HRESULT hr;
428
429 TRACE("(%p,%p)\n", iface, pIPalette);
430
431 if (!This->palette)
432 {
433 IWICPalette *new_palette;
434 hr = PaletteImpl_Create(&new_palette);
435
436 if (FAILED(hr)) return hr;
437
438 if (InterlockedCompareExchangePointer((void**)&This->palette, new_palette, NULL))
439 {
440 /* someone beat us to it */
441 IWICPalette_Release(new_palette);
442 }
443 }
444
445 hr = IWICPalette_InitializeFromPalette(This->palette, pIPalette);
446
447 if (SUCCEEDED(hr))
448 This->palette_set = 1;
449
450 return S_OK;
451 }
452
453 static HRESULT WINAPI BitmapImpl_SetResolution(IWICBitmap *iface,
454 double dpiX, double dpiY)
455 {
456 BitmapImpl *This = impl_from_IWICBitmap(iface);
457 TRACE("(%p,%f,%f)\n", iface, dpiX, dpiY);
458
459 EnterCriticalSection(&This->cs);
460 This->dpix = dpiX;
461 This->dpiy = dpiY;
462 LeaveCriticalSection(&This->cs);
463
464 return S_OK;
465 }
466
467 static const IWICBitmapVtbl BitmapImpl_Vtbl = {
468 BitmapImpl_QueryInterface,
469 BitmapImpl_AddRef,
470 BitmapImpl_Release,
471 BitmapImpl_GetSize,
472 BitmapImpl_GetPixelFormat,
473 BitmapImpl_GetResolution,
474 BitmapImpl_CopyPalette,
475 BitmapImpl_CopyPixels,
476 BitmapImpl_Lock,
477 BitmapImpl_SetPalette,
478 BitmapImpl_SetResolution
479 };
480
481 static HRESULT WINAPI IMILBitmapImpl_QueryInterface(IMILBitmapSource *iface, REFIID iid,
482 void **ppv)
483 {
484 BitmapImpl *This = impl_from_IMILBitmapSource(iface);
485 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
486
487 if (!ppv) return E_INVALIDARG;
488
489 if (IsEqualIID(&IID_IUnknown, iid) ||
490 IsEqualIID(&IID_IMILBitmap, iid) ||
491 IsEqualIID(&IID_IMILBitmapSource, iid))
492 {
493 IUnknown_AddRef(&This->IMILBitmapSource_iface);
494 *ppv = &This->IMILBitmapSource_iface;
495 return S_OK;
496 }
497 else if (IsEqualIID(&IID_IWICBitmap, iid) ||
498 IsEqualIID(&IID_IWICBitmapSource, iid))
499 {
500 IUnknown_AddRef(&This->IWICBitmap_iface);
501 *ppv = &This->IWICBitmap_iface;
502 return S_OK;
503 }
504
505 FIXME("unknown interface %s\n", debugstr_guid(iid));
506 *ppv = NULL;
507 return E_NOINTERFACE;
508 }
509
510 static ULONG WINAPI IMILBitmapImpl_AddRef(IMILBitmapSource *iface)
511 {
512 BitmapImpl *This = impl_from_IMILBitmapSource(iface);
513 return IWICBitmap_AddRef(&This->IWICBitmap_iface);
514 }
515
516 static ULONG WINAPI IMILBitmapImpl_Release(IMILBitmapSource *iface)
517 {
518 BitmapImpl *This = impl_from_IMILBitmapSource(iface);
519 return IWICBitmap_Release(&This->IWICBitmap_iface);
520 }
521
522 static HRESULT WINAPI IMILBitmapImpl_GetSize(IMILBitmapSource *iface,
523 UINT *width, UINT *height)
524 {
525 BitmapImpl *This = impl_from_IMILBitmapSource(iface);
526 TRACE("(%p,%p,%p)\n", iface, width, height);
527 return IWICBitmap_GetSize(&This->IWICBitmap_iface, width, height);
528 }
529
530 static const struct
531 {
532 const GUID *WIC_format;
533 int enum_format;
534 } pixel_fmt_map[] =
535 {
536 { &GUID_WICPixelFormatDontCare, 0 },
537 { &GUID_WICPixelFormat1bppIndexed, 1 },
538 { &GUID_WICPixelFormat2bppIndexed, 2 },
539 { &GUID_WICPixelFormat4bppIndexed, 3 },
540 { &GUID_WICPixelFormat8bppIndexed, 4 },
541 { &GUID_WICPixelFormatBlackWhite, 5 },
542 { &GUID_WICPixelFormat2bppGray, 6 },
543 { &GUID_WICPixelFormat4bppGray, 7 },
544 { &GUID_WICPixelFormat8bppGray, 8 },
545 { &GUID_WICPixelFormat16bppBGR555, 9 },
546 { &GUID_WICPixelFormat16bppBGR565, 0x0a },
547 { &GUID_WICPixelFormat16bppGray, 0x0b },
548 { &GUID_WICPixelFormat24bppBGR, 0x0c },
549 { &GUID_WICPixelFormat24bppRGB, 0x0d },
550 { &GUID_WICPixelFormat32bppBGR, 0x0e },
551 { &GUID_WICPixelFormat32bppBGRA, 0x0f },
552 { &GUID_WICPixelFormat32bppPBGRA, 0x10 },
553 { &GUID_WICPixelFormat48bppRGB, 0x15 },
554 { &GUID_WICPixelFormat64bppRGBA, 0x16 },
555 { &GUID_WICPixelFormat64bppPRGBA, 0x17 },
556 { &GUID_WICPixelFormat32bppCMYK, 0x1c }
557 };
558
559 static HRESULT WINAPI IMILBitmapImpl_GetPixelFormat(IMILBitmapSource *iface,
560 int *format)
561 {
562 BitmapImpl *This = impl_from_IMILBitmapSource(iface);
563 int i;
564
565 TRACE("(%p,%p)\n", iface, format);
566
567 if (!format) return E_INVALIDARG;
568
569 *format = 0;
570
571 for (i = 0; i < ARRAY_SIZE(pixel_fmt_map); i++)
572 {
573 if (IsEqualGUID(pixel_fmt_map[i].WIC_format, &This->pixelformat))
574 {
575 *format = pixel_fmt_map[i].enum_format;
576 break;
577 }
578 }
579
580 TRACE("=> %u\n", *format);
581 return S_OK;
582 }
583
584 static HRESULT WINAPI IMILBitmapImpl_GetResolution(IMILBitmapSource *iface,
585 double *dpix, double *dpiy)
586 {
587 BitmapImpl *This = impl_from_IMILBitmapSource(iface);
588 TRACE("(%p,%p,%p)\n", iface, dpix, dpiy);
589 return IWICBitmap_GetResolution(&This->IWICBitmap_iface, dpix, dpiy);
590 }
591
592 static HRESULT WINAPI IMILBitmapImpl_CopyPalette(IMILBitmapSource *iface,
593 IWICPalette *palette)
594 {
595 BitmapImpl *This = impl_from_IMILBitmapSource(iface);
596 TRACE("(%p,%p)\n", iface, palette);
597 return IWICBitmap_CopyPalette(&This->IWICBitmap_iface, palette);
598 }
599
600 static HRESULT WINAPI IMILBitmapImpl_CopyPixels(IMILBitmapSource *iface,
601 const WICRect *rc, UINT stride, UINT size, BYTE *buffer)
602 {
603 BitmapImpl *This = impl_from_IMILBitmapSource(iface);
604 TRACE("(%p,%p,%u,%u,%p)\n", iface, rc, stride, size, buffer);
605 return IWICBitmap_CopyPixels(&This->IWICBitmap_iface, rc, stride, size, buffer);
606 }
607
608 static HRESULT WINAPI IMILBitmapImpl_unknown1(IMILBitmapSource *iface, void **ppv)
609 {
610 BitmapImpl *This = impl_from_IMILBitmapSource(iface);
611
612 TRACE("(%p,%p)\n", iface, ppv);
613
614 if (!ppv) return E_INVALIDARG;
615
616 /* reference count is not incremented here */
617 *ppv = &This->IMILUnknown1_iface;
618
619 return S_OK;
620 }
621
622 static HRESULT WINAPI IMILBitmapImpl_Lock(IMILBitmapSource *iface, const WICRect *rc, DWORD flags, IWICBitmapLock **lock)
623 {
624 BitmapImpl *This = impl_from_IMILBitmapSource(iface);
625 TRACE("(%p,%p,%08x,%p)\n", iface, rc, flags, lock);
626 return IWICBitmap_Lock(&This->IWICBitmap_iface, rc, flags, lock);
627 }
628
629 static HRESULT WINAPI IMILBitmapImpl_Unlock(IMILBitmapSource *iface, IWICBitmapLock *lock)
630 {
631 TRACE("(%p,%p)\n", iface, lock);
632 IWICBitmapLock_Release(lock);
633 return S_OK;
634 }
635
636 static HRESULT WINAPI IMILBitmapImpl_SetPalette(IMILBitmapSource *iface, IWICPalette *palette)
637 {
638 BitmapImpl *This = impl_from_IMILBitmapSource(iface);
639 TRACE("(%p,%p)\n", iface, palette);
640 return IWICBitmap_SetPalette(&This->IWICBitmap_iface, palette);
641 }
642
643 static HRESULT WINAPI IMILBitmapImpl_SetResolution(IMILBitmapSource *iface, double dpix, double dpiy)
644 {
645 BitmapImpl *This = impl_from_IMILBitmapSource(iface);
646 TRACE("(%p,%f,%f)\n", iface, dpix, dpiy);
647 return IWICBitmap_SetResolution(&This->IWICBitmap_iface, dpix, dpiy);
648 }
649
650 static HRESULT WINAPI IMILBitmapImpl_AddDirtyRect(IMILBitmapSource *iface, const WICRect *rc)
651 {
652 FIXME("(%p,%p): stub\n", iface, rc);
653 return E_NOTIMPL;
654 }
655
656 static const IMILBitmapSourceVtbl IMILBitmapImpl_Vtbl =
657 {
658 IMILBitmapImpl_QueryInterface,
659 IMILBitmapImpl_AddRef,
660 IMILBitmapImpl_Release,
661 IMILBitmapImpl_GetSize,
662 IMILBitmapImpl_GetPixelFormat,
663 IMILBitmapImpl_GetResolution,
664 IMILBitmapImpl_CopyPalette,
665 IMILBitmapImpl_CopyPixels,
666 IMILBitmapImpl_unknown1,
667 IMILBitmapImpl_Lock,
668 IMILBitmapImpl_Unlock,
669 IMILBitmapImpl_SetPalette,
670 IMILBitmapImpl_SetResolution,
671 IMILBitmapImpl_AddDirtyRect
672 };
673
674 static HRESULT WINAPI IMILUnknown1Impl_QueryInterface(IMILUnknown1 *iface, REFIID iid,
675 void **ppv)
676 {
677 FIXME("(%p,%s,%p): stub\n", iface, debugstr_guid(iid), ppv);
678 *ppv = NULL;
679 return E_NOINTERFACE;
680 }
681
682 static ULONG WINAPI IMILUnknown1Impl_AddRef(IMILUnknown1 *iface)
683 {
684 BitmapImpl *This = impl_from_IMILUnknown1(iface);
685 return IWICBitmap_AddRef(&This->IWICBitmap_iface);
686 }
687
688 static ULONG WINAPI IMILUnknown1Impl_Release(IMILUnknown1 *iface)
689 {
690 BitmapImpl *This = impl_from_IMILUnknown1(iface);
691 return IWICBitmap_Release(&This->IWICBitmap_iface);
692 }
693
694 DECLSPEC_HIDDEN void WINAPI IMILUnknown1Impl_unknown1(IMILUnknown1 *iface, void *arg)
695 {
696 FIXME("(%p,%p): stub\n", iface, arg);
697 }
698
699 static HRESULT WINAPI IMILUnknown1Impl_unknown2(IMILUnknown1 *iface, void *arg1, void *arg2)
700 {
701 FIXME("(%p,%p,%p): stub\n", iface, arg1, arg2);
702 return E_NOTIMPL;
703 }
704
705 DECLSPEC_HIDDEN HRESULT WINAPI IMILUnknown1Impl_unknown3(IMILUnknown1 *iface, void *arg)
706 {
707 FIXME("(%p,%p): stub\n", iface, arg);
708 return E_NOTIMPL;
709 }
710
711 static HRESULT WINAPI IMILUnknown1Impl_unknown4(IMILUnknown1 *iface, void *arg)
712 {
713 FIXME("(%p,%p): stub\n", iface, arg);
714 return E_NOTIMPL;
715 }
716
717 static HRESULT WINAPI IMILUnknown1Impl_unknown5(IMILUnknown1 *iface, void *arg)
718 {
719 FIXME("(%p,%p): stub\n", iface, arg);
720 return E_NOTIMPL;
721 }
722
723 static HRESULT WINAPI IMILUnknown1Impl_unknown6(IMILUnknown1 *iface, DWORD64 arg)
724 {
725 FIXME("(%p,%s): stub\n", iface, wine_dbgstr_longlong(arg));
726 return E_NOTIMPL;
727 }
728
729 static HRESULT WINAPI IMILUnknown1Impl_unknown7(IMILUnknown1 *iface, void *arg)
730 {
731 FIXME("(%p,%p): stub\n", iface, arg);
732 return E_NOTIMPL;
733 }
734
735 DECLSPEC_HIDDEN HRESULT WINAPI IMILUnknown1Impl_unknown8(IMILUnknown1 *iface)
736 {
737 FIXME("(%p): stub\n", iface);
738 return E_NOTIMPL;
739 }
740
741 DEFINE_THISCALL_WRAPPER(IMILUnknown1Impl_unknown1, 8)
742 DEFINE_THISCALL_WRAPPER(IMILUnknown1Impl_unknown3, 8)
743 DEFINE_THISCALL_WRAPPER(IMILUnknown1Impl_unknown8, 4)
744
745 static const IMILUnknown1Vtbl IMILUnknown1Impl_Vtbl =
746 {
747 IMILUnknown1Impl_QueryInterface,
748 IMILUnknown1Impl_AddRef,
749 IMILUnknown1Impl_Release,
750 THISCALL(IMILUnknown1Impl_unknown1),
751 IMILUnknown1Impl_unknown2,
752 THISCALL(IMILUnknown1Impl_unknown3),
753 IMILUnknown1Impl_unknown4,
754 IMILUnknown1Impl_unknown5,
755 IMILUnknown1Impl_unknown6,
756 IMILUnknown1Impl_unknown7,
757 THISCALL(IMILUnknown1Impl_unknown8)
758 };
759
760 static HRESULT WINAPI IMILUnknown2Impl_QueryInterface(IMILUnknown2 *iface, REFIID iid,
761 void **ppv)
762 {
763 FIXME("(%p,%s,%p): stub\n", iface, debugstr_guid(iid), ppv);
764 *ppv = NULL;
765 return E_NOINTERFACE;
766 }
767
768 static ULONG WINAPI IMILUnknown2Impl_AddRef(IMILUnknown2 *iface)
769 {
770 FIXME("(%p): stub\n", iface);
771 return 0;
772 }
773
774 static ULONG WINAPI IMILUnknown2Impl_Release(IMILUnknown2 *iface)
775 {
776 FIXME("(%p): stub\n", iface);
777 return 0;
778 }
779
780 static HRESULT WINAPI IMILUnknown2Impl_unknown1(IMILUnknown2 *iface, void *arg1, void **arg2)
781 {
782 FIXME("(%p,%p,%p): stub\n", iface, arg1, arg2);
783 if (arg2) *arg2 = NULL;
784 return E_NOTIMPL;
785 }
786
787 static HRESULT WINAPI IMILUnknown2Impl_unknown2(IMILUnknown2 *iface, void *arg1, void *arg2)
788 {
789 FIXME("(%p,%p,%p): stub\n", iface, arg1, arg2);
790 return E_NOTIMPL;
791 }
792
793 static HRESULT WINAPI IMILUnknown2Impl_unknown3(IMILUnknown2 *iface, void *arg1)
794 {
795 FIXME("(%p,%p): stub\n", iface, arg1);
796 return E_NOTIMPL;
797 }
798
799 static const IMILUnknown2Vtbl IMILUnknown2Impl_Vtbl =
800 {
801 IMILUnknown2Impl_QueryInterface,
802 IMILUnknown2Impl_AddRef,
803 IMILUnknown2Impl_Release,
804 IMILUnknown2Impl_unknown1,
805 IMILUnknown2Impl_unknown2,
806 IMILUnknown2Impl_unknown3
807 };
808
809 HRESULT BitmapImpl_Create(UINT uiWidth, UINT uiHeight, UINT stride, UINT datasize, void *view,
810 UINT offset, REFWICPixelFormatGUID pixelFormat, WICBitmapCreateCacheOption option,
811 IWICBitmap **ppIBitmap)
812 {
813 HRESULT hr;
814 BitmapImpl *This;
815 BYTE *data;
816 UINT bpp;
817
818 hr = get_pixelformat_bpp(pixelFormat, &bpp);
819 if (FAILED(hr)) return hr;
820
821 if (!stride) stride = (((bpp*uiWidth)+31)/32)*4;
822 if (!datasize) datasize = stride * uiHeight;
823
824 if (datasize < stride * uiHeight) return WINCODEC_ERR_INSUFFICIENTBUFFER;
825 if (stride < ((bpp*uiWidth)+7)/8) return E_INVALIDARG;
826
827 This = HeapAlloc(GetProcessHeap(), 0, sizeof(BitmapImpl));
828 if (!This) return E_OUTOFMEMORY;
829
830 if (view) data = (BYTE *)view + offset;
831 else if (!(data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, datasize)))
832 {
833 HeapFree(GetProcessHeap(), 0, This);
834 return E_OUTOFMEMORY;
835 }
836
837 This->IWICBitmap_iface.lpVtbl = &BitmapImpl_Vtbl;
838 This->IMILBitmapSource_iface.lpVtbl = &IMILBitmapImpl_Vtbl;
839 This->IMILUnknown1_iface.lpVtbl = &IMILUnknown1Impl_Vtbl;
840 This->IMILUnknown2_iface.lpVtbl = &IMILUnknown2Impl_Vtbl;
841 This->ref = 1;
842 This->palette = NULL;
843 This->palette_set = 0;
844 This->lock = 0;
845 This->data = data;
846 This->view = view;
847 This->offset = offset;
848 This->width = uiWidth;
849 This->height = uiHeight;
850 This->stride = stride;
851 This->bpp = bpp;
852 memcpy(&This->pixelformat, pixelFormat, sizeof(GUID));
853 This->dpix = This->dpiy = 0.0;
854 InitializeCriticalSection(&This->cs);
855 This->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": BitmapImpl.lock");
856
857 *ppIBitmap = &This->IWICBitmap_iface;
858
859 return S_OK;
860 }