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