xref: /reactos/dll/win32/windowscodecs/bitmap.c (revision d5399189)
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,%p,%u,%u,%p)\n", iface, 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,%p,%x,%p)\n", iface, 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 < sizeof(pixel_fmt_map)/sizeof(pixel_fmt_map[0]); 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 }
861