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