Always define WIDL_C_INLINE_WRAPPERS.
[wine] / dlls / windowscodecs / gifformat.c
1 /*
2  * Copyright 2009 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 #include "wincodec.h"
29
30 #include "ungif.h"
31
32 #include "wincodecs_private.h"
33
34 #include "wine/debug.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
37
38 typedef struct {
39     IWICBitmapDecoder IWICBitmapDecoder_iface;
40     LONG ref;
41     BOOL initialized;
42     GifFileType *gif;
43     CRITICAL_SECTION lock;
44 } GifDecoder;
45
46 typedef struct {
47     IWICBitmapFrameDecode IWICBitmapFrameDecode_iface;
48     LONG ref;
49     SavedImage *frame;
50     GifDecoder *parent;
51 } GifFrameDecode;
52
53 static inline GifDecoder *impl_from_IWICBitmapDecoder(IWICBitmapDecoder *iface)
54 {
55     return CONTAINING_RECORD(iface, GifDecoder, IWICBitmapDecoder_iface);
56 }
57
58 static inline GifFrameDecode *impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode *iface)
59 {
60     return CONTAINING_RECORD(iface, GifFrameDecode, IWICBitmapFrameDecode_iface);
61 }
62
63 static HRESULT WINAPI GifFrameDecode_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid,
64     void **ppv)
65 {
66     GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
67     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
68
69     if (!ppv) return E_INVALIDARG;
70
71     if (IsEqualIID(&IID_IUnknown, iid) ||
72         IsEqualIID(&IID_IWICBitmapSource, iid) ||
73         IsEqualIID(&IID_IWICBitmapFrameDecode, iid))
74     {
75         *ppv = &This->IWICBitmapFrameDecode_iface;
76     }
77     else
78     {
79         *ppv = NULL;
80         return E_NOINTERFACE;
81     }
82
83     IUnknown_AddRef((IUnknown*)*ppv);
84     return S_OK;
85 }
86
87 static ULONG WINAPI GifFrameDecode_AddRef(IWICBitmapFrameDecode *iface)
88 {
89     GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
90     ULONG ref = InterlockedIncrement(&This->ref);
91
92     TRACE("(%p) refcount=%u\n", iface, ref);
93
94     return ref;
95 }
96
97 static ULONG WINAPI GifFrameDecode_Release(IWICBitmapFrameDecode *iface)
98 {
99     GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
100     ULONG ref = InterlockedDecrement(&This->ref);
101
102     TRACE("(%p) refcount=%u\n", iface, ref);
103
104     if (ref == 0)
105     {
106         IUnknown_Release((IUnknown*)This->parent);
107         HeapFree(GetProcessHeap(), 0, This);
108     }
109
110     return ref;
111 }
112
113 static HRESULT WINAPI GifFrameDecode_GetSize(IWICBitmapFrameDecode *iface,
114     UINT *puiWidth, UINT *puiHeight)
115 {
116     GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
117     TRACE("(%p,%p,%p)\n", iface, puiWidth, puiHeight);
118
119     *puiWidth = This->frame->ImageDesc.Width;
120     *puiHeight = This->frame->ImageDesc.Height;
121
122     return S_OK;
123 }
124
125 static HRESULT WINAPI GifFrameDecode_GetPixelFormat(IWICBitmapFrameDecode *iface,
126     WICPixelFormatGUID *pPixelFormat)
127 {
128     memcpy(pPixelFormat, &GUID_WICPixelFormat8bppIndexed, sizeof(GUID));
129
130     return S_OK;
131 }
132
133 static HRESULT WINAPI GifFrameDecode_GetResolution(IWICBitmapFrameDecode *iface,
134     double *pDpiX, double *pDpiY)
135 {
136     GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
137     const GifWord aspect_word = This->parent->gif->SAspectRatio;
138     const double aspect = (aspect_word > 0) ? ((aspect_word + 15.0) / 64.0) : 1.0;
139     TRACE("(%p,%p,%p)\n", iface, pDpiX, pDpiY);
140
141     *pDpiX = 96.0 / aspect;
142     *pDpiY = 96.0;
143
144     return S_OK;
145 }
146
147 static HRESULT WINAPI GifFrameDecode_CopyPalette(IWICBitmapFrameDecode *iface,
148     IWICPalette *pIPalette)
149 {
150     GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
151     WICColor colors[256];
152     ColorMapObject *cm = This->frame->ImageDesc.ColorMap;
153     int i, trans;
154     ExtensionBlock *eb;
155     TRACE("(%p,%p)\n", iface, pIPalette);
156
157     if (!cm) cm = This->parent->gif->SColorMap;
158
159     if (cm->ColorCount > 256)
160     {
161         ERR("GIF contains %i colors???\n", cm->ColorCount);
162         return E_FAIL;
163     }
164
165     for (i = 0; i < cm->ColorCount; i++) {
166         colors[i] = 0xff000000| /* alpha */
167                     cm->Colors[i].Red << 16|
168                     cm->Colors[i].Green << 8|
169                     cm->Colors[i].Blue;
170     }
171
172     /* look for the transparent color extension */
173     for (i = 0; i < This->frame->ExtensionBlockCount; ++i) {
174         eb = This->frame->ExtensionBlocks + i;
175         if (eb->Function == 0xF9 && eb->ByteCount == 4) {
176             if ((eb->Bytes[0] & 1) == 1) {
177                 trans = (unsigned char)eb->Bytes[3];
178                 colors[trans] &= 0xffffff; /* set alpha to 0 */
179                 break;
180             }
181         }
182     }
183
184     IWICPalette_InitializeCustom(pIPalette, colors, cm->ColorCount);
185
186     return S_OK;
187 }
188
189 static HRESULT copy_interlaced_pixels(const BYTE *srcbuffer,
190     UINT srcwidth, UINT srcheight, INT srcstride, const WICRect *rc,
191     UINT dststride, UINT dstbuffersize, BYTE *dstbuffer)
192 {
193     UINT row_offset; /* number of bytes into the source rows where the data starts */
194     const BYTE *src;
195     BYTE *dst;
196     UINT y;
197     WICRect rect;
198
199     if (!rc)
200     {
201         rect.X = 0;
202         rect.Y = 0;
203         rect.Width = srcwidth;
204         rect.Height = srcheight;
205         rc = &rect;
206     }
207     else
208     {
209         if (rc->X < 0 || rc->Y < 0 || rc->X+rc->Width > srcwidth || rc->Y+rc->Height > srcheight)
210             return E_INVALIDARG;
211     }
212
213     if (dststride < rc->Width)
214         return E_INVALIDARG;
215
216     if ((dststride * rc->Height) > dstbuffersize)
217         return E_INVALIDARG;
218
219     row_offset = rc->X;
220
221     dst = dstbuffer;
222     for (y=rc->Y; y-rc->Y < rc->Height; y++)
223     {
224         if (y%8 == 0)
225             src = srcbuffer + srcstride * (y/8);
226         else if (y%4 == 0)
227             src = srcbuffer + srcstride * ((srcheight+7)/8 + y/8);
228         else if (y%2 == 0)
229             src = srcbuffer + srcstride * ((srcheight+3)/4 + y/4);
230         else /* y%2 == 1 */
231             src = srcbuffer + srcstride * ((srcheight+1)/2 + y/2);
232         src += row_offset;
233         memcpy(dst, src, rc->Width);
234         dst += dststride;
235     }
236     return S_OK;
237 }
238
239 static HRESULT WINAPI GifFrameDecode_CopyPixels(IWICBitmapFrameDecode *iface,
240     const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
241 {
242     GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
243     TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer);
244
245     if (This->frame->ImageDesc.Interlace)
246     {
247         return copy_interlaced_pixels(This->frame->RasterBits, This->frame->ImageDesc.Width,
248             This->frame->ImageDesc.Height, This->frame->ImageDesc.Width,
249             prc, cbStride, cbBufferSize, pbBuffer);
250     }
251     else
252     {
253         return copy_pixels(8, This->frame->RasterBits, This->frame->ImageDesc.Width,
254             This->frame->ImageDesc.Height, This->frame->ImageDesc.Width,
255             prc, cbStride, cbBufferSize, pbBuffer);
256     }
257 }
258
259 static HRESULT WINAPI GifFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode *iface,
260     IWICMetadataQueryReader **ppIMetadataQueryReader)
261 {
262     TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader);
263     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
264 }
265
266 static HRESULT WINAPI GifFrameDecode_GetColorContexts(IWICBitmapFrameDecode *iface,
267     UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
268 {
269     TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount);
270     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
271 }
272
273 static HRESULT WINAPI GifFrameDecode_GetThumbnail(IWICBitmapFrameDecode *iface,
274     IWICBitmapSource **ppIThumbnail)
275 {
276     TRACE("(%p,%p)\n", iface, ppIThumbnail);
277     return WINCODEC_ERR_CODECNOTHUMBNAIL;
278 }
279
280 static const IWICBitmapFrameDecodeVtbl GifFrameDecode_Vtbl = {
281     GifFrameDecode_QueryInterface,
282     GifFrameDecode_AddRef,
283     GifFrameDecode_Release,
284     GifFrameDecode_GetSize,
285     GifFrameDecode_GetPixelFormat,
286     GifFrameDecode_GetResolution,
287     GifFrameDecode_CopyPalette,
288     GifFrameDecode_CopyPixels,
289     GifFrameDecode_GetMetadataQueryReader,
290     GifFrameDecode_GetColorContexts,
291     GifFrameDecode_GetThumbnail
292 };
293
294 static HRESULT WINAPI GifDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid,
295     void **ppv)
296 {
297     GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
298     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
299
300     if (!ppv) return E_INVALIDARG;
301
302     if (IsEqualIID(&IID_IUnknown, iid) ||
303         IsEqualIID(&IID_IWICBitmapDecoder, iid))
304     {
305         *ppv = &This->IWICBitmapDecoder_iface;
306     }
307     else
308     {
309         *ppv = NULL;
310         return E_NOINTERFACE;
311     }
312
313     IUnknown_AddRef((IUnknown*)*ppv);
314     return S_OK;
315 }
316
317 static ULONG WINAPI GifDecoder_AddRef(IWICBitmapDecoder *iface)
318 {
319     GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
320     ULONG ref = InterlockedIncrement(&This->ref);
321
322     TRACE("(%p) refcount=%u\n", iface, ref);
323
324     return ref;
325 }
326
327 static ULONG WINAPI GifDecoder_Release(IWICBitmapDecoder *iface)
328 {
329     GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
330     ULONG ref = InterlockedDecrement(&This->ref);
331
332     TRACE("(%p) refcount=%u\n", iface, ref);
333
334     if (ref == 0)
335     {
336         This->lock.DebugInfo->Spare[0] = 0;
337         DeleteCriticalSection(&This->lock);
338         DGifCloseFile(This->gif);
339         HeapFree(GetProcessHeap(), 0, This);
340     }
341
342     return ref;
343 }
344
345 static HRESULT WINAPI GifDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *pIStream,
346     DWORD *pdwCapability)
347 {
348     FIXME("(%p,%p,%p): stub\n", iface, pIStream, pdwCapability);
349     return E_NOTIMPL;
350 }
351
352 static int _gif_inputfunc(GifFileType *gif, GifByteType *data, int len) {
353     IStream *stream = gif->UserData;
354     ULONG bytesread;
355     HRESULT hr;
356
357     if (!stream)
358     {
359         ERR("attempting to read file after initialization\n");
360         return 0;
361     }
362
363     hr = IStream_Read(stream, data, len, &bytesread);
364     if (hr != S_OK) bytesread = 0;
365     return bytesread;
366 }
367
368 static HRESULT WINAPI GifDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream,
369     WICDecodeOptions cacheOptions)
370 {
371     GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
372     LARGE_INTEGER seek;
373     int ret;
374
375     TRACE("(%p,%p,%x)\n", iface, pIStream, cacheOptions);
376
377     EnterCriticalSection(&This->lock);
378
379     if (This->initialized || This->gif)
380     {
381         WARN("already initialized\n");
382         LeaveCriticalSection(&This->lock);
383         return WINCODEC_ERR_WRONGSTATE;
384     }
385
386     /* seek to start of stream */
387     seek.QuadPart = 0;
388     IStream_Seek(pIStream, seek, STREAM_SEEK_SET, NULL);
389
390     /* read all data from the stream */
391     This->gif = DGifOpen((void*)pIStream, _gif_inputfunc);
392     if (!This->gif)
393     {
394         LeaveCriticalSection(&This->lock);
395         return E_FAIL;
396     }
397
398     ret = DGifSlurp(This->gif);
399     if (ret == GIF_ERROR)
400     {
401         LeaveCriticalSection(&This->lock);
402         return E_FAIL;
403     }
404
405     /* make sure we don't use the stream after this method returns */
406     This->gif->UserData = NULL;
407
408     This->initialized = TRUE;
409
410     LeaveCriticalSection(&This->lock);
411
412     return S_OK;
413 }
414
415 static HRESULT WINAPI GifDecoder_GetContainerFormat(IWICBitmapDecoder *iface,
416     GUID *pguidContainerFormat)
417 {
418     memcpy(pguidContainerFormat, &GUID_ContainerFormatGif, sizeof(GUID));
419     return S_OK;
420 }
421
422 static HRESULT WINAPI GifDecoder_GetDecoderInfo(IWICBitmapDecoder *iface,
423     IWICBitmapDecoderInfo **ppIDecoderInfo)
424 {
425     HRESULT hr;
426     IWICComponentInfo *compinfo;
427
428     TRACE("(%p,%p)\n", iface, ppIDecoderInfo);
429
430     hr = CreateComponentInfo(&CLSID_WICGifDecoder, &compinfo);
431     if (FAILED(hr)) return hr;
432
433     hr = IWICComponentInfo_QueryInterface(compinfo, &IID_IWICBitmapDecoderInfo,
434         (void**)ppIDecoderInfo);
435
436     IWICComponentInfo_Release(compinfo);
437
438     return hr;
439 }
440
441 static HRESULT WINAPI GifDecoder_CopyPalette(IWICBitmapDecoder *iface,
442     IWICPalette *pIPalette)
443 {
444     TRACE("(%p,%p)\n", iface, pIPalette);
445     return WINCODEC_ERR_PALETTEUNAVAILABLE;
446 }
447
448 static HRESULT WINAPI GifDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface,
449     IWICMetadataQueryReader **ppIMetadataQueryReader)
450 {
451     TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader);
452     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
453 }
454
455 static HRESULT WINAPI GifDecoder_GetPreview(IWICBitmapDecoder *iface,
456     IWICBitmapSource **ppIBitmapSource)
457 {
458     TRACE("(%p,%p)\n", iface, ppIBitmapSource);
459     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
460 }
461
462 static HRESULT WINAPI GifDecoder_GetColorContexts(IWICBitmapDecoder *iface,
463     UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
464 {
465     TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount);
466     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
467 }
468
469 static HRESULT WINAPI GifDecoder_GetThumbnail(IWICBitmapDecoder *iface,
470     IWICBitmapSource **ppIThumbnail)
471 {
472     TRACE("(%p,%p)\n", iface, ppIThumbnail);
473     return WINCODEC_ERR_CODECNOTHUMBNAIL;
474 }
475
476 static HRESULT WINAPI GifDecoder_GetFrameCount(IWICBitmapDecoder *iface,
477     UINT *pCount)
478 {
479     GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
480     TRACE("(%p,%p)\n", iface, pCount);
481
482     if (!This->initialized) return WINCODEC_ERR_NOTINITIALIZED;
483
484     *pCount = This->gif->ImageCount;
485
486     TRACE("<- %u\n", *pCount);
487
488     return S_OK;
489 }
490
491 static HRESULT WINAPI GifDecoder_GetFrame(IWICBitmapDecoder *iface,
492     UINT index, IWICBitmapFrameDecode **ppIBitmapFrame)
493 {
494     GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
495     GifFrameDecode *result;
496     TRACE("(%p,%u,%p)\n", iface, index, ppIBitmapFrame);
497
498     if (!This->initialized) return WINCODEC_ERR_NOTINITIALIZED;
499
500     if (index >= This->gif->ImageCount) return E_INVALIDARG;
501
502     result = HeapAlloc(GetProcessHeap(), 0, sizeof(GifFrameDecode));
503     if (!result) return E_OUTOFMEMORY;
504
505     result->IWICBitmapFrameDecode_iface.lpVtbl = &GifFrameDecode_Vtbl;
506     result->ref = 1;
507     result->frame = &This->gif->SavedImages[index];
508     IWICBitmapDecoder_AddRef(iface);
509     result->parent = This;
510
511     *ppIBitmapFrame = &result->IWICBitmapFrameDecode_iface;
512
513     return S_OK;
514 }
515
516 static const IWICBitmapDecoderVtbl GifDecoder_Vtbl = {
517     GifDecoder_QueryInterface,
518     GifDecoder_AddRef,
519     GifDecoder_Release,
520     GifDecoder_QueryCapability,
521     GifDecoder_Initialize,
522     GifDecoder_GetContainerFormat,
523     GifDecoder_GetDecoderInfo,
524     GifDecoder_CopyPalette,
525     GifDecoder_GetMetadataQueryReader,
526     GifDecoder_GetPreview,
527     GifDecoder_GetColorContexts,
528     GifDecoder_GetThumbnail,
529     GifDecoder_GetFrameCount,
530     GifDecoder_GetFrame
531 };
532
533 HRESULT GifDecoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
534 {
535     GifDecoder *This;
536     HRESULT ret;
537
538     TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv);
539
540     *ppv = NULL;
541
542     if (pUnkOuter) return CLASS_E_NOAGGREGATION;
543
544     This = HeapAlloc(GetProcessHeap(), 0, sizeof(GifDecoder));
545     if (!This) return E_OUTOFMEMORY;
546
547     This->IWICBitmapDecoder_iface.lpVtbl = &GifDecoder_Vtbl;
548     This->ref = 1;
549     This->initialized = FALSE;
550     This->gif = NULL;
551     InitializeCriticalSection(&This->lock);
552     This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": GifDecoder.lock");
553
554     ret = IWICBitmapDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv);
555     IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface);
556
557     return ret;
558 }