dwrite: Stub for CreateMonitorRenderingParams().
[wine] / dlls / windowscodecs / gifformat.c
1 /*
2  * Copyright 2009 Vincent Povirk for CodeWeavers
3  * Copyright 2012 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 #include "config.h"
21
22 #include <stdarg.h>
23
24 #define COBJMACROS
25 #define NONAMELESSUNION
26
27 #include "windef.h"
28 #include "winbase.h"
29 #include "objbase.h"
30 #include "wincodec.h"
31 #include "wincodecsdk.h"
32
33 #include "ungif.h"
34
35 #include "wincodecs_private.h"
36
37 #include "wine/debug.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
40
41 static LPWSTR strdupAtoW(const char *src)
42 {
43     int len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0);
44     LPWSTR dst = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
45     if (dst) MultiByteToWideChar(CP_ACP, 0, src, -1, dst, len);
46     return dst;
47 }
48
49 static HRESULT load_LSD_metadata(IStream *stream, const GUID *vendor, DWORD options,
50                                  MetadataItem **items, DWORD *count)
51 {
52 #include "pshpack1.h"
53     struct logical_screen_descriptor
54     {
55         char signature[6];
56         USHORT width;
57         USHORT height;
58         BYTE packed;
59         /* global_color_table_flag : 1;
60          * color_resolution : 3;
61          * sort_flag : 1;
62          * global_color_table_size : 3;
63          */
64         BYTE background_color_index;
65         BYTE pixel_aspect_ratio;
66     } lsd_data;
67 #include "poppack.h"
68     HRESULT hr;
69     ULONG bytesread, i;
70     MetadataItem *result;
71
72     *items = NULL;
73     *count = 0;
74
75     hr = IStream_Read(stream, &lsd_data, sizeof(lsd_data), &bytesread);
76     if (FAILED(hr) || bytesread != sizeof(lsd_data)) return S_OK;
77
78     result = HeapAlloc(GetProcessHeap(), 0, sizeof(MetadataItem) * 9);
79     if (!result) return E_OUTOFMEMORY;
80
81     for (i = 0; i < 9; i++)
82     {
83         PropVariantInit(&result[i].schema);
84         PropVariantInit(&result[i].id);
85         PropVariantInit(&result[i].value);
86     }
87
88     result[0].id.vt = VT_LPWSTR;
89     result[0].id.u.pwszVal = strdupAtoW("Signature");
90     result[0].value.vt = VT_UI1|VT_VECTOR;
91     result[0].value.u.caub.cElems = sizeof(lsd_data.signature);
92     result[0].value.u.caub.pElems = HeapAlloc(GetProcessHeap(), 0, sizeof(lsd_data.signature));
93     memcpy(result[0].value.u.caub.pElems, lsd_data.signature, sizeof(lsd_data.signature));
94
95     result[1].id.vt = VT_LPWSTR;
96     result[1].id.u.pwszVal = strdupAtoW("Width");
97     result[1].value.vt = VT_UI2;
98     result[1].value.u.uiVal = lsd_data.width;
99
100     result[2].id.vt = VT_LPWSTR;
101     result[2].id.u.pwszVal = strdupAtoW("Height");
102     result[2].value.vt = VT_UI2;
103     result[2].value.u.uiVal = lsd_data.height;
104
105     result[3].id.vt = VT_LPWSTR;
106     result[3].id.u.pwszVal = strdupAtoW("GlobalColorTableFlag");
107     result[3].value.vt = VT_BOOL;
108     result[3].value.u.boolVal = (lsd_data.packed >> 7) & 1;
109
110     result[4].id.vt = VT_LPWSTR;
111     result[4].id.u.pwszVal = strdupAtoW("ColorResolution");
112     result[4].value.vt = VT_UI1;
113     result[4].value.u.bVal = (lsd_data.packed >> 4) & 7;
114
115     result[5].id.vt = VT_LPWSTR;
116     result[5].id.u.pwszVal = strdupAtoW("SortFlag");
117     result[5].value.vt = VT_BOOL;
118     result[5].value.u.boolVal = (lsd_data.packed >> 3) & 1;
119
120     result[6].id.vt = VT_LPWSTR;
121     result[6].id.u.pwszVal = strdupAtoW("GlobalColorTableSize");
122     result[6].value.vt = VT_UI1;
123     result[6].value.u.bVal = lsd_data.packed & 7;
124
125     result[7].id.vt = VT_LPWSTR;
126     result[7].id.u.pwszVal = strdupAtoW("BackgroundColorIndex");
127     result[7].value.vt = VT_UI1;
128     result[7].value.u.bVal = lsd_data.background_color_index;
129
130     result[8].id.vt = VT_LPWSTR;
131     result[8].id.u.pwszVal = strdupAtoW("PixelAspectRatio");
132     result[8].value.vt = VT_UI1;
133     result[8].value.u.bVal = lsd_data.pixel_aspect_ratio;
134
135     *items = result;
136     *count = 9;
137
138     return S_OK;
139 }
140
141 static const MetadataHandlerVtbl LSDReader_Vtbl = {
142     0,
143     &CLSID_WICLSDMetadataReader,
144     load_LSD_metadata
145 };
146
147 HRESULT LSDReader_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void **ppv)
148 {
149     return MetadataReader_Create(&LSDReader_Vtbl, pUnkOuter, iid, ppv);
150 }
151
152 #include "pshpack1.h"
153 struct image_descriptor
154 {
155     USHORT left;
156     USHORT top;
157     USHORT width;
158     USHORT height;
159     BYTE packed;
160     /* local_color_table_flag : 1;
161      * interlace_flag : 1;
162      * sort_flag : 1;
163      * reserved : 2;
164      * local_color_table_size : 3;
165      */
166 };
167 #include "poppack.h"
168
169 static HRESULT load_IMD_metadata(IStream *stream, const GUID *vendor, DWORD options,
170                                  MetadataItem **items, DWORD *count)
171 {
172     struct image_descriptor imd_data;
173     HRESULT hr;
174     ULONG bytesread, i;
175     MetadataItem *result;
176
177     *items = NULL;
178     *count = 0;
179
180     hr = IStream_Read(stream, &imd_data, sizeof(imd_data), &bytesread);
181     if (FAILED(hr) || bytesread != sizeof(imd_data)) return S_OK;
182
183     result = HeapAlloc(GetProcessHeap(), 0, sizeof(MetadataItem) * 8);
184     if (!result) return E_OUTOFMEMORY;
185
186     for (i = 0; i < 8; i++)
187     {
188         PropVariantInit(&result[i].schema);
189         PropVariantInit(&result[i].id);
190         PropVariantInit(&result[i].value);
191     }
192
193     result[0].id.vt = VT_LPWSTR;
194     result[0].id.u.pwszVal = strdupAtoW("Left");
195     result[0].value.vt = VT_UI2;
196     result[0].value.u.uiVal = imd_data.left;
197
198     result[1].id.vt = VT_LPWSTR;
199     result[1].id.u.pwszVal = strdupAtoW("Top");
200     result[1].value.vt = VT_UI2;
201     result[1].value.u.uiVal = imd_data.top;
202
203     result[2].id.vt = VT_LPWSTR;
204     result[2].id.u.pwszVal = strdupAtoW("Width");
205     result[2].value.vt = VT_UI2;
206     result[2].value.u.uiVal = imd_data.width;
207
208     result[3].id.vt = VT_LPWSTR;
209     result[3].id.u.pwszVal = strdupAtoW("Height");
210     result[3].value.vt = VT_UI2;
211     result[3].value.u.uiVal = imd_data.height;
212
213     result[4].id.vt = VT_LPWSTR;
214     result[4].id.u.pwszVal = strdupAtoW("LocalColorTableFlag");
215     result[4].value.vt = VT_BOOL;
216     result[4].value.u.boolVal = (imd_data.packed >> 7) & 1;
217
218     result[5].id.vt = VT_LPWSTR;
219     result[5].id.u.pwszVal = strdupAtoW("InterlaceFlag");
220     result[5].value.vt = VT_BOOL;
221     result[5].value.u.boolVal = (imd_data.packed >> 6) & 1;
222
223     result[6].id.vt = VT_LPWSTR;
224     result[6].id.u.pwszVal = strdupAtoW("SortFlag");
225     result[6].value.vt = VT_BOOL;
226     result[6].value.u.boolVal = (imd_data.packed >> 5) & 1;
227
228     result[7].id.vt = VT_LPWSTR;
229     result[7].id.u.pwszVal = strdupAtoW("LocalColorTableSize");
230     result[7].value.vt = VT_UI1;
231     result[7].value.u.bVal = imd_data.packed & 7;
232
233     *items = result;
234     *count = 8;
235
236     return S_OK;
237 }
238
239 static const MetadataHandlerVtbl IMDReader_Vtbl = {
240     0,
241     &CLSID_WICIMDMetadataReader,
242     load_IMD_metadata
243 };
244
245 HRESULT IMDReader_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void **ppv)
246 {
247     return MetadataReader_Create(&IMDReader_Vtbl, pUnkOuter, iid, ppv);
248 }
249
250 static HRESULT load_GCE_metadata(IStream *stream, const GUID *vendor, DWORD options,
251                                  MetadataItem **items, DWORD *count)
252 {
253 #include "pshpack1.h"
254     struct graphic_control_extenstion
255     {
256         BYTE packed;
257         /* reservred: 3;
258          * disposal : 3;
259          * user_input_flag : 1;
260          * transparency_flag : 1;
261          */
262          USHORT delay;
263          BYTE transparent_color_index;
264     } gce_data;
265 #include "poppack.h"
266     HRESULT hr;
267     ULONG bytesread, i;
268     MetadataItem *result;
269
270     *items = NULL;
271     *count = 0;
272
273     hr = IStream_Read(stream, &gce_data, sizeof(gce_data), &bytesread);
274     if (FAILED(hr) || bytesread != sizeof(gce_data)) return S_OK;
275
276     result = HeapAlloc(GetProcessHeap(), 0, sizeof(MetadataItem) * 5);
277     if (!result) return E_OUTOFMEMORY;
278
279     for (i = 0; i < 5; i++)
280     {
281         PropVariantInit(&result[i].schema);
282         PropVariantInit(&result[i].id);
283         PropVariantInit(&result[i].value);
284     }
285
286     result[0].id.vt = VT_LPWSTR;
287     result[0].id.u.pwszVal = strdupAtoW("Disposal");
288     result[0].value.vt = VT_UI1;
289     result[0].value.u.bVal = (gce_data.packed >> 2) & 7;
290
291     result[1].id.vt = VT_LPWSTR;
292     result[1].id.u.pwszVal = strdupAtoW("UserInputFlag");
293     result[1].value.vt = VT_BOOL;
294     result[1].value.u.boolVal = (gce_data.packed >> 1) & 1;
295
296     result[2].id.vt = VT_LPWSTR;
297     result[2].id.u.pwszVal = strdupAtoW("TransparencyFlag");
298     result[2].value.vt = VT_BOOL;
299     result[2].value.u.boolVal = gce_data.packed & 1;
300
301     result[3].id.vt = VT_LPWSTR;
302     result[3].id.u.pwszVal = strdupAtoW("Delay");
303     result[3].value.vt = VT_UI2;
304     result[3].value.u.uiVal = gce_data.delay;
305
306     result[4].id.vt = VT_LPWSTR;
307     result[4].id.u.pwszVal = strdupAtoW("TransparentColorIndex");
308     result[4].value.vt = VT_UI1;
309     result[4].value.u.bVal = gce_data.transparent_color_index;
310
311     *items = result;
312     *count = 5;
313
314     return S_OK;
315 }
316
317 static const MetadataHandlerVtbl GCEReader_Vtbl = {
318     0,
319     &CLSID_WICGCEMetadataReader,
320     load_GCE_metadata
321 };
322
323 HRESULT GCEReader_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void **ppv)
324 {
325     return MetadataReader_Create(&GCEReader_Vtbl, pUnkOuter, iid, ppv);
326 }
327
328 static HRESULT load_APE_metadata(IStream *stream, const GUID *vendor, DWORD options,
329                                  MetadataItem **items, DWORD *count)
330 {
331 #include "pshpack1.h"
332     struct application_extenstion
333     {
334         BYTE extension_introducer;
335         BYTE extension_label;
336         BYTE block_size;
337         BYTE application[11];
338     } ape_data;
339 #include "poppack.h"
340     HRESULT hr;
341     ULONG bytesread, data_size, i;
342     MetadataItem *result;
343     BYTE subblock_size;
344     BYTE *data;
345
346     *items = NULL;
347     *count = 0;
348
349     hr = IStream_Read(stream, &ape_data, sizeof(ape_data), &bytesread);
350     if (FAILED(hr) || bytesread != sizeof(ape_data)) return S_OK;
351     if (ape_data.extension_introducer != 0x21 ||
352         ape_data.extension_label != APPLICATION_EXT_FUNC_CODE ||
353         ape_data.block_size != 11)
354         return S_OK;
355
356     data = NULL;
357     data_size = 0;
358
359     for (;;)
360     {
361         hr = IStream_Read(stream, &subblock_size, sizeof(subblock_size), &bytesread);
362         if (FAILED(hr) || bytesread != sizeof(subblock_size))
363         {
364             HeapFree(GetProcessHeap(), 0, data);
365             return S_OK;
366         }
367         if (!subblock_size) break;
368
369         if (!data)
370             data = HeapAlloc(GetProcessHeap(), 0, subblock_size + 1);
371         else
372         {
373             BYTE *new_data = HeapReAlloc(GetProcessHeap(), 0, data, data_size + subblock_size + 1);
374             if (!new_data)
375             {
376                 HeapFree(GetProcessHeap(), 0, data);
377                 return S_OK;
378             }
379             data = new_data;
380         }
381         data[data_size] = subblock_size;
382         hr = IStream_Read(stream, data + data_size + 1, subblock_size, &bytesread);
383         if (FAILED(hr) || bytesread != subblock_size)
384         {
385             HeapFree(GetProcessHeap(), 0, data);
386             return S_OK;
387         }
388         data_size += subblock_size + 1;
389     }
390
391     result = HeapAlloc(GetProcessHeap(), 0, sizeof(MetadataItem) * 2);
392     if (!result)
393     {
394         HeapFree(GetProcessHeap(), 0, data);
395         return E_OUTOFMEMORY;
396     }
397
398     for (i = 0; i < 2; i++)
399     {
400         PropVariantInit(&result[i].schema);
401         PropVariantInit(&result[i].id);
402         PropVariantInit(&result[i].value);
403     }
404
405     result[0].id.vt = VT_LPWSTR;
406     result[0].id.u.pwszVal = strdupAtoW("Application");
407     result[0].value.vt = VT_UI1|VT_VECTOR;
408     result[0].value.u.caub.cElems = sizeof(ape_data.application);
409     result[0].value.u.caub.pElems = HeapAlloc(GetProcessHeap(), 0, sizeof(ape_data.application));
410     memcpy(result[0].value.u.caub.pElems, ape_data.application, sizeof(ape_data.application));
411
412     result[1].id.vt = VT_LPWSTR;
413     result[1].id.u.pwszVal = strdupAtoW("Data");
414     result[1].value.vt = VT_UI1|VT_VECTOR;
415     result[1].value.u.caub.cElems = data_size;
416     result[1].value.u.caub.pElems = data;
417
418     *items = result;
419     *count = 2;
420
421     return S_OK;
422 }
423
424 static const MetadataHandlerVtbl APEReader_Vtbl = {
425     0,
426     &CLSID_WICAPEMetadataReader,
427     load_APE_metadata
428 };
429
430 HRESULT APEReader_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void **ppv)
431 {
432     return MetadataReader_Create(&APEReader_Vtbl, pUnkOuter, iid, ppv);
433 }
434
435 static HRESULT load_GifComment_metadata(IStream *stream, const GUID *vendor, DWORD options,
436                                         MetadataItem **items, DWORD *count)
437 {
438 #include "pshpack1.h"
439     struct gif_extenstion
440     {
441         BYTE extension_introducer;
442         BYTE extension_label;
443     } ext_data;
444 #include "poppack.h"
445     HRESULT hr;
446     ULONG bytesread, data_size;
447     MetadataItem *result;
448     BYTE subblock_size;
449     char *data;
450
451     *items = NULL;
452     *count = 0;
453
454     hr = IStream_Read(stream, &ext_data, sizeof(ext_data), &bytesread);
455     if (FAILED(hr) || bytesread != sizeof(ext_data)) return S_OK;
456     if (ext_data.extension_introducer != 0x21 ||
457         ext_data.extension_label != COMMENT_EXT_FUNC_CODE)
458         return S_OK;
459
460     data = NULL;
461     data_size = 0;
462
463     for (;;)
464     {
465         hr = IStream_Read(stream, &subblock_size, sizeof(subblock_size), &bytesread);
466         if (FAILED(hr) || bytesread != sizeof(subblock_size))
467         {
468             HeapFree(GetProcessHeap(), 0, data);
469             return S_OK;
470         }
471         if (!subblock_size) break;
472
473         if (!data)
474             data = HeapAlloc(GetProcessHeap(), 0, subblock_size + 1);
475         else
476         {
477             char *new_data = HeapReAlloc(GetProcessHeap(), 0, data, data_size + subblock_size + 1);
478             if (!new_data)
479             {
480                 HeapFree(GetProcessHeap(), 0, data);
481                 return S_OK;
482             }
483             data = new_data;
484         }
485         hr = IStream_Read(stream, data + data_size, subblock_size, &bytesread);
486         if (FAILED(hr) || bytesread != subblock_size)
487         {
488             HeapFree(GetProcessHeap(), 0, data);
489             return S_OK;
490         }
491         data_size += subblock_size;
492     }
493
494     data[data_size] = 0;
495
496     result = HeapAlloc(GetProcessHeap(), 0, sizeof(MetadataItem));
497     if (!result)
498     {
499         HeapFree(GetProcessHeap(), 0, data);
500         return E_OUTOFMEMORY;
501     }
502
503     PropVariantInit(&result->schema);
504     PropVariantInit(&result->id);
505     PropVariantInit(&result->value);
506
507     result->id.vt = VT_LPWSTR;
508     result->id.u.pwszVal = strdupAtoW("TextEntry");
509     result->value.vt = VT_LPSTR;
510     result->value.u.pszVal = data;
511
512     *items = result;
513     *count = 1;
514
515     return S_OK;
516 }
517
518 static const MetadataHandlerVtbl GifCommentReader_Vtbl = {
519     0,
520     &CLSID_WICGifCommentMetadataReader,
521     load_GifComment_metadata
522 };
523
524 HRESULT GifCommentReader_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void **ppv)
525 {
526     return MetadataReader_Create(&GifCommentReader_Vtbl, pUnkOuter, iid, ppv);
527 }
528
529 static IStream *create_stream(const void *data, int data_size)
530 {
531     HRESULT hr;
532     IStream *stream;
533     HGLOBAL hdata;
534     void *locked_data;
535
536     hdata = GlobalAlloc(GMEM_MOVEABLE, data_size);
537     if (!hdata) return NULL;
538
539     locked_data = GlobalLock(hdata);
540     memcpy(locked_data, data, data_size);
541     GlobalUnlock(hdata);
542
543     hr = CreateStreamOnHGlobal(hdata, TRUE, &stream);
544     return FAILED(hr) ? NULL : stream;
545 }
546
547 static HRESULT create_metadata_reader(const void *data, int data_size,
548                                       const CLSID *clsid, IWICMetadataReader **reader)
549 {
550     HRESULT hr;
551     IWICMetadataReader *metadata_reader;
552     IWICPersistStream *persist;
553     IStream *stream;
554
555     /* FIXME: Use IWICComponentFactory_CreateMetadataReader once it's implemented */
556
557     hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER,
558                           &IID_IWICMetadataReader, (void **)&metadata_reader);
559     if (FAILED(hr)) return hr;
560
561     hr = IWICMetadataReader_QueryInterface(metadata_reader, &IID_IWICPersistStream, (void **)&persist);
562     if (FAILED(hr))
563     {
564         IWICMetadataReader_Release(metadata_reader);
565         return hr;
566     }
567
568     stream = create_stream(data, data_size);
569     IWICPersistStream_LoadEx(persist, stream, NULL, WICPersistOptionsDefault);
570     IStream_Release(stream);
571
572     IWICPersistStream_Release(persist);
573
574     *reader = metadata_reader;
575     return S_OK;
576 }
577
578 typedef struct {
579     IWICBitmapDecoder IWICBitmapDecoder_iface;
580     IWICMetadataBlockReader IWICMetadataBlockReader_iface;
581     BYTE LSD_data[13]; /* Logical Screen Descriptor */
582     LONG ref;
583     BOOL initialized;
584     GifFileType *gif;
585     UINT current_frame;
586     CRITICAL_SECTION lock;
587 } GifDecoder;
588
589 typedef struct {
590     IWICBitmapFrameDecode IWICBitmapFrameDecode_iface;
591     IWICMetadataBlockReader IWICMetadataBlockReader_iface;
592     LONG ref;
593     SavedImage *frame;
594     GifDecoder *parent;
595 } GifFrameDecode;
596
597 static inline GifDecoder *impl_from_IWICBitmapDecoder(IWICBitmapDecoder *iface)
598 {
599     return CONTAINING_RECORD(iface, GifDecoder, IWICBitmapDecoder_iface);
600 }
601
602 static inline GifDecoder *impl_from_IWICMetadataBlockReader(IWICMetadataBlockReader *iface)
603 {
604     return CONTAINING_RECORD(iface, GifDecoder, IWICMetadataBlockReader_iface);
605 }
606
607 static inline GifFrameDecode *impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode *iface)
608 {
609     return CONTAINING_RECORD(iface, GifFrameDecode, IWICBitmapFrameDecode_iface);
610 }
611
612 static inline GifFrameDecode *frame_from_IWICMetadataBlockReader(IWICMetadataBlockReader *iface)
613 {
614     return CONTAINING_RECORD(iface, GifFrameDecode, IWICMetadataBlockReader_iface);
615 }
616
617 static HRESULT WINAPI GifFrameDecode_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid,
618     void **ppv)
619 {
620     GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
621     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
622
623     if (!ppv) return E_INVALIDARG;
624
625     if (IsEqualIID(&IID_IUnknown, iid) ||
626         IsEqualIID(&IID_IWICBitmapSource, iid) ||
627         IsEqualIID(&IID_IWICBitmapFrameDecode, iid))
628     {
629         *ppv = &This->IWICBitmapFrameDecode_iface;
630     }
631     else if (IsEqualIID(&IID_IWICMetadataBlockReader, iid))
632     {
633         *ppv = &This->IWICMetadataBlockReader_iface;
634     }
635     else
636     {
637         *ppv = NULL;
638         return E_NOINTERFACE;
639     }
640
641     IUnknown_AddRef((IUnknown*)*ppv);
642     return S_OK;
643 }
644
645 static ULONG WINAPI GifFrameDecode_AddRef(IWICBitmapFrameDecode *iface)
646 {
647     GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
648     ULONG ref = InterlockedIncrement(&This->ref);
649
650     TRACE("(%p) refcount=%u\n", iface, ref);
651
652     return ref;
653 }
654
655 static ULONG WINAPI GifFrameDecode_Release(IWICBitmapFrameDecode *iface)
656 {
657     GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
658     ULONG ref = InterlockedDecrement(&This->ref);
659
660     TRACE("(%p) refcount=%u\n", iface, ref);
661
662     if (ref == 0)
663     {
664         IWICBitmapDecoder_Release(&This->parent->IWICBitmapDecoder_iface);
665         HeapFree(GetProcessHeap(), 0, This);
666     }
667
668     return ref;
669 }
670
671 static HRESULT WINAPI GifFrameDecode_GetSize(IWICBitmapFrameDecode *iface,
672     UINT *puiWidth, UINT *puiHeight)
673 {
674     GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
675     TRACE("(%p,%p,%p)\n", iface, puiWidth, puiHeight);
676
677     *puiWidth = This->frame->ImageDesc.Width;
678     *puiHeight = This->frame->ImageDesc.Height;
679
680     return S_OK;
681 }
682
683 static HRESULT WINAPI GifFrameDecode_GetPixelFormat(IWICBitmapFrameDecode *iface,
684     WICPixelFormatGUID *pPixelFormat)
685 {
686     memcpy(pPixelFormat, &GUID_WICPixelFormat8bppIndexed, sizeof(GUID));
687
688     return S_OK;
689 }
690
691 static HRESULT WINAPI GifFrameDecode_GetResolution(IWICBitmapFrameDecode *iface,
692     double *pDpiX, double *pDpiY)
693 {
694     GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
695     const GifWord aspect_word = This->parent->gif->SAspectRatio;
696     const double aspect = (aspect_word > 0) ? ((aspect_word + 15.0) / 64.0) : 1.0;
697     TRACE("(%p,%p,%p)\n", iface, pDpiX, pDpiY);
698
699     *pDpiX = 96.0 / aspect;
700     *pDpiY = 96.0;
701
702     return S_OK;
703 }
704
705 static HRESULT WINAPI GifFrameDecode_CopyPalette(IWICBitmapFrameDecode *iface,
706     IWICPalette *pIPalette)
707 {
708     GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
709     WICColor colors[256];
710     ColorMapObject *cm = This->frame->ImageDesc.ColorMap;
711     int i, trans;
712     ExtensionBlock *eb;
713     TRACE("(%p,%p)\n", iface, pIPalette);
714
715     if (!cm) cm = This->parent->gif->SColorMap;
716
717     if (cm->ColorCount > 256)
718     {
719         ERR("GIF contains %i colors???\n", cm->ColorCount);
720         return E_FAIL;
721     }
722
723     for (i = 0; i < cm->ColorCount; i++) {
724         colors[i] = 0xff000000| /* alpha */
725                     cm->Colors[i].Red << 16|
726                     cm->Colors[i].Green << 8|
727                     cm->Colors[i].Blue;
728     }
729
730     /* look for the transparent color extension */
731     for (i = 0; i < This->frame->Extensions.ExtensionBlockCount; ++i) {
732         eb = This->frame->Extensions.ExtensionBlocks + i;
733         if (eb->Function == GRAPHICS_EXT_FUNC_CODE && eb->ByteCount == 8) {
734             if (eb->Bytes[3] & 1) {
735                 trans = (unsigned char)eb->Bytes[6];
736                 colors[trans] &= 0xffffff; /* set alpha to 0 */
737                 break;
738             }
739         }
740     }
741
742     return IWICPalette_InitializeCustom(pIPalette, colors, cm->ColorCount);
743 }
744
745 static HRESULT copy_interlaced_pixels(const BYTE *srcbuffer,
746     UINT srcwidth, UINT srcheight, INT srcstride, const WICRect *rc,
747     UINT dststride, UINT dstbuffersize, BYTE *dstbuffer)
748 {
749     UINT row_offset; /* number of bytes into the source rows where the data starts */
750     const BYTE *src;
751     BYTE *dst;
752     UINT y;
753     WICRect rect;
754
755     if (!rc)
756     {
757         rect.X = 0;
758         rect.Y = 0;
759         rect.Width = srcwidth;
760         rect.Height = srcheight;
761         rc = &rect;
762     }
763     else
764     {
765         if (rc->X < 0 || rc->Y < 0 || rc->X+rc->Width > srcwidth || rc->Y+rc->Height > srcheight)
766             return E_INVALIDARG;
767     }
768
769     if (dststride < rc->Width)
770         return E_INVALIDARG;
771
772     if ((dststride * rc->Height) > dstbuffersize)
773         return E_INVALIDARG;
774
775     row_offset = rc->X;
776
777     dst = dstbuffer;
778     for (y=rc->Y; y-rc->Y < rc->Height; y++)
779     {
780         if (y%8 == 0)
781             src = srcbuffer + srcstride * (y/8);
782         else if (y%4 == 0)
783             src = srcbuffer + srcstride * ((srcheight+7)/8 + y/8);
784         else if (y%2 == 0)
785             src = srcbuffer + srcstride * ((srcheight+3)/4 + y/4);
786         else /* y%2 == 1 */
787             src = srcbuffer + srcstride * ((srcheight+1)/2 + y/2);
788         src += row_offset;
789         memcpy(dst, src, rc->Width);
790         dst += dststride;
791     }
792     return S_OK;
793 }
794
795 static HRESULT WINAPI GifFrameDecode_CopyPixels(IWICBitmapFrameDecode *iface,
796     const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
797 {
798     GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
799     TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer);
800
801     if (This->frame->ImageDesc.Interlace)
802     {
803         return copy_interlaced_pixels(This->frame->RasterBits, This->frame->ImageDesc.Width,
804             This->frame->ImageDesc.Height, This->frame->ImageDesc.Width,
805             prc, cbStride, cbBufferSize, pbBuffer);
806     }
807     else
808     {
809         return copy_pixels(8, This->frame->RasterBits, This->frame->ImageDesc.Width,
810             This->frame->ImageDesc.Height, This->frame->ImageDesc.Width,
811             prc, cbStride, cbBufferSize, pbBuffer);
812     }
813 }
814
815 static HRESULT WINAPI GifFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode *iface,
816     IWICMetadataQueryReader **ppIMetadataQueryReader)
817 {
818     TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader);
819     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
820 }
821
822 static HRESULT WINAPI GifFrameDecode_GetColorContexts(IWICBitmapFrameDecode *iface,
823     UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
824 {
825     TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount);
826     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
827 }
828
829 static HRESULT WINAPI GifFrameDecode_GetThumbnail(IWICBitmapFrameDecode *iface,
830     IWICBitmapSource **ppIThumbnail)
831 {
832     TRACE("(%p,%p)\n", iface, ppIThumbnail);
833     return WINCODEC_ERR_CODECNOTHUMBNAIL;
834 }
835
836 static const IWICBitmapFrameDecodeVtbl GifFrameDecode_Vtbl = {
837     GifFrameDecode_QueryInterface,
838     GifFrameDecode_AddRef,
839     GifFrameDecode_Release,
840     GifFrameDecode_GetSize,
841     GifFrameDecode_GetPixelFormat,
842     GifFrameDecode_GetResolution,
843     GifFrameDecode_CopyPalette,
844     GifFrameDecode_CopyPixels,
845     GifFrameDecode_GetMetadataQueryReader,
846     GifFrameDecode_GetColorContexts,
847     GifFrameDecode_GetThumbnail
848 };
849
850 static HRESULT WINAPI GifFrameDecode_Block_QueryInterface(IWICMetadataBlockReader *iface,
851     REFIID iid, void **ppv)
852 {
853     GifFrameDecode *This = frame_from_IWICMetadataBlockReader(iface);
854     return IWICBitmapFrameDecode_QueryInterface(&This->IWICBitmapFrameDecode_iface, iid, ppv);
855 }
856
857 static ULONG WINAPI GifFrameDecode_Block_AddRef(IWICMetadataBlockReader *iface)
858 {
859     GifFrameDecode *This = frame_from_IWICMetadataBlockReader(iface);
860     return IWICBitmapFrameDecode_AddRef(&This->IWICBitmapFrameDecode_iface);
861 }
862
863 static ULONG WINAPI GifFrameDecode_Block_Release(IWICMetadataBlockReader *iface)
864 {
865     GifFrameDecode *This = frame_from_IWICMetadataBlockReader(iface);
866     return IWICBitmapFrameDecode_Release(&This->IWICBitmapFrameDecode_iface);
867 }
868
869 static HRESULT WINAPI GifFrameDecode_Block_GetContainerFormat(IWICMetadataBlockReader *iface,
870     GUID *guid)
871 {
872     TRACE("(%p,%p)\n", iface, guid);
873
874     if (!guid) return E_INVALIDARG;
875
876     *guid = GUID_ContainerFormatGif;
877     return S_OK;
878 }
879
880 static HRESULT WINAPI GifFrameDecode_Block_GetCount(IWICMetadataBlockReader *iface,
881     UINT *count)
882 {
883     GifFrameDecode *This = frame_from_IWICMetadataBlockReader(iface);
884
885     TRACE("%p,%p\n", iface, count);
886
887     if (!count) return E_INVALIDARG;
888
889     *count = This->frame->Extensions.ExtensionBlockCount + 1;
890     return S_OK;
891 }
892
893 static HRESULT create_IMD_metadata_reader(GifFrameDecode *This, IWICMetadataReader **reader)
894 {
895     HRESULT hr;
896     IWICMetadataReader *metadata_reader;
897     IWICPersistStream *persist;
898     IStream *stream;
899     struct image_descriptor IMD_data;
900
901     /* FIXME: Use IWICComponentFactory_CreateMetadataReader once it's implemented */
902
903     hr = CoCreateInstance(&CLSID_WICIMDMetadataReader, NULL, CLSCTX_INPROC_SERVER,
904                           &IID_IWICMetadataReader, (void **)&metadata_reader);
905     if (FAILED(hr)) return hr;
906
907     hr = IWICMetadataReader_QueryInterface(metadata_reader, &IID_IWICPersistStream, (void **)&persist);
908     if (FAILED(hr))
909     {
910         IWICMetadataReader_Release(metadata_reader);
911         return hr;
912     }
913
914     /* recreate IMD structure from GIF decoder data */
915     IMD_data.left = This->frame->ImageDesc.Left;
916     IMD_data.top = This->frame->ImageDesc.Top;
917     IMD_data.width = This->frame->ImageDesc.Width;
918     IMD_data.height = This->frame->ImageDesc.Height;
919     IMD_data.packed = 0;
920     /* interlace_flag */
921     IMD_data.packed |= This->frame->ImageDesc.Interlace ? (1 << 6) : 0;
922     if (This->frame->ImageDesc.ColorMap)
923     {
924         /* local_color_table_flag */
925         IMD_data.packed |= 1 << 7;
926         /* local_color_table_size */
927         IMD_data.packed |= This->frame->ImageDesc.ColorMap->BitsPerPixel - 1;
928         /* sort_flag */
929         IMD_data.packed |= This->frame->ImageDesc.ColorMap->SortFlag ? 0x20 : 0;
930     }
931
932     stream = create_stream(&IMD_data, sizeof(IMD_data));
933     IWICPersistStream_LoadEx(persist, stream, NULL, WICPersistOptionsDefault);
934     IStream_Release(stream);
935
936     IWICPersistStream_Release(persist);
937
938     *reader = metadata_reader;
939     return S_OK;
940 }
941
942 static HRESULT WINAPI GifFrameDecode_Block_GetReaderByIndex(IWICMetadataBlockReader *iface,
943     UINT index, IWICMetadataReader **reader)
944 {
945     GifFrameDecode *This = frame_from_IWICMetadataBlockReader(iface);
946     int i, gce_index = -1, gce_skipped = 0;
947
948     TRACE("(%p,%u,%p)\n", iface, index, reader);
949
950     if (!reader) return E_INVALIDARG;
951
952     if (index == 0)
953         return create_IMD_metadata_reader(This, reader);
954
955     if (index >= This->frame->Extensions.ExtensionBlockCount + 1)
956         return E_INVALIDARG;
957
958     for (i = 0; i < This->frame->Extensions.ExtensionBlockCount; i++)
959     {
960         const CLSID *clsid;
961         const void *data;
962         int data_size;
963
964         if (index != i + 1 - gce_skipped) continue;
965
966         if (This->frame->Extensions.ExtensionBlocks[i].Function == GRAPHICS_EXT_FUNC_CODE)
967         {
968             gce_index = i;
969             gce_skipped = 1;
970             continue;
971         }
972         else if (This->frame->Extensions.ExtensionBlocks[i].Function == COMMENT_EXT_FUNC_CODE)
973         {
974             clsid = &CLSID_WICGifCommentMetadataReader;
975             data = This->frame->Extensions.ExtensionBlocks[i].Bytes;
976             data_size = This->frame->Extensions.ExtensionBlocks[i].ByteCount;
977         }
978         else
979         {
980             clsid = &CLSID_WICUnknownMetadataReader;
981             data = This->frame->Extensions.ExtensionBlocks[i].Bytes;
982             data_size = This->frame->Extensions.ExtensionBlocks[i].ByteCount;
983         }
984         return create_metadata_reader(data, data_size, clsid, reader);
985     }
986
987     if (gce_index == -1) return E_INVALIDARG;
988
989     return create_metadata_reader(This->frame->Extensions.ExtensionBlocks[gce_index].Bytes + 3,
990                                   This->frame->Extensions.ExtensionBlocks[gce_index].ByteCount - 4,
991                                   &CLSID_WICGCEMetadataReader, reader);
992 }
993
994 static HRESULT WINAPI GifFrameDecode_Block_GetEnumerator(IWICMetadataBlockReader *iface,
995     IEnumUnknown **enumerator)
996 {
997     FIXME("(%p,%p): stub\n", iface, enumerator);
998     return E_NOTIMPL;
999 }
1000
1001 static const IWICMetadataBlockReaderVtbl GifFrameDecode_BlockVtbl =
1002 {
1003     GifFrameDecode_Block_QueryInterface,
1004     GifFrameDecode_Block_AddRef,
1005     GifFrameDecode_Block_Release,
1006     GifFrameDecode_Block_GetContainerFormat,
1007     GifFrameDecode_Block_GetCount,
1008     GifFrameDecode_Block_GetReaderByIndex,
1009     GifFrameDecode_Block_GetEnumerator
1010 };
1011
1012 static HRESULT WINAPI GifDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid,
1013     void **ppv)
1014 {
1015     GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
1016     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
1017
1018     if (!ppv) return E_INVALIDARG;
1019
1020     if (IsEqualIID(&IID_IUnknown, iid) ||
1021         IsEqualIID(&IID_IWICBitmapDecoder, iid))
1022     {
1023         *ppv = &This->IWICBitmapDecoder_iface;
1024     }
1025     else if (IsEqualIID(&IID_IWICMetadataBlockReader, iid))
1026     {
1027         *ppv = &This->IWICMetadataBlockReader_iface;
1028     }
1029     else
1030     {
1031         *ppv = NULL;
1032         return E_NOINTERFACE;
1033     }
1034
1035     IUnknown_AddRef((IUnknown*)*ppv);
1036     return S_OK;
1037 }
1038
1039 static ULONG WINAPI GifDecoder_AddRef(IWICBitmapDecoder *iface)
1040 {
1041     GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
1042     ULONG ref = InterlockedIncrement(&This->ref);
1043
1044     TRACE("(%p) refcount=%u\n", iface, ref);
1045
1046     return ref;
1047 }
1048
1049 static ULONG WINAPI GifDecoder_Release(IWICBitmapDecoder *iface)
1050 {
1051     GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
1052     ULONG ref = InterlockedDecrement(&This->ref);
1053
1054     TRACE("(%p) refcount=%u\n", iface, ref);
1055
1056     if (ref == 0)
1057     {
1058         This->lock.DebugInfo->Spare[0] = 0;
1059         DeleteCriticalSection(&This->lock);
1060         DGifCloseFile(This->gif);
1061         HeapFree(GetProcessHeap(), 0, This);
1062     }
1063
1064     return ref;
1065 }
1066
1067 static HRESULT WINAPI GifDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *pIStream,
1068     DWORD *pdwCapability)
1069 {
1070     FIXME("(%p,%p,%p): stub\n", iface, pIStream, pdwCapability);
1071     return E_NOTIMPL;
1072 }
1073
1074 static int _gif_inputfunc(GifFileType *gif, GifByteType *data, int len) {
1075     IStream *stream = gif->UserData;
1076     ULONG bytesread;
1077     HRESULT hr;
1078
1079     if (!stream)
1080     {
1081         ERR("attempting to read file after initialization\n");
1082         return 0;
1083     }
1084
1085     hr = IStream_Read(stream, data, len, &bytesread);
1086     if (hr != S_OK) bytesread = 0;
1087     return bytesread;
1088 }
1089
1090 static HRESULT WINAPI GifDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream,
1091     WICDecodeOptions cacheOptions)
1092 {
1093     GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
1094     LARGE_INTEGER seek;
1095     int ret;
1096
1097     TRACE("(%p,%p,%x)\n", iface, pIStream, cacheOptions);
1098
1099     EnterCriticalSection(&This->lock);
1100
1101     if (This->initialized || This->gif)
1102     {
1103         WARN("already initialized\n");
1104         LeaveCriticalSection(&This->lock);
1105         return WINCODEC_ERR_WRONGSTATE;
1106     }
1107
1108     /* seek to start of stream */
1109     seek.QuadPart = 0;
1110     IStream_Seek(pIStream, seek, STREAM_SEEK_SET, NULL);
1111
1112     /* read all data from the stream */
1113     This->gif = DGifOpen((void*)pIStream, _gif_inputfunc);
1114     if (!This->gif)
1115     {
1116         LeaveCriticalSection(&This->lock);
1117         return E_FAIL;
1118     }
1119
1120     ret = DGifSlurp(This->gif);
1121     if (ret == GIF_ERROR)
1122     {
1123         LeaveCriticalSection(&This->lock);
1124         return E_FAIL;
1125     }
1126
1127     /* make sure we don't use the stream after this method returns */
1128     This->gif->UserData = NULL;
1129
1130     seek.QuadPart = 0;
1131     IStream_Seek(pIStream, seek, STREAM_SEEK_SET, NULL);
1132     IStream_Read(pIStream, &This->LSD_data, sizeof(This->LSD_data), NULL);
1133
1134     This->initialized = TRUE;
1135
1136     LeaveCriticalSection(&This->lock);
1137
1138     return S_OK;
1139 }
1140
1141 static HRESULT WINAPI GifDecoder_GetContainerFormat(IWICBitmapDecoder *iface,
1142     GUID *pguidContainerFormat)
1143 {
1144     memcpy(pguidContainerFormat, &GUID_ContainerFormatGif, sizeof(GUID));
1145     return S_OK;
1146 }
1147
1148 static HRESULT WINAPI GifDecoder_GetDecoderInfo(IWICBitmapDecoder *iface,
1149     IWICBitmapDecoderInfo **ppIDecoderInfo)
1150 {
1151     HRESULT hr;
1152     IWICComponentInfo *compinfo;
1153
1154     TRACE("(%p,%p)\n", iface, ppIDecoderInfo);
1155
1156     hr = CreateComponentInfo(&CLSID_WICGifDecoder, &compinfo);
1157     if (FAILED(hr)) return hr;
1158
1159     hr = IWICComponentInfo_QueryInterface(compinfo, &IID_IWICBitmapDecoderInfo,
1160         (void**)ppIDecoderInfo);
1161
1162     IWICComponentInfo_Release(compinfo);
1163
1164     return hr;
1165 }
1166
1167 static HRESULT WINAPI GifDecoder_CopyPalette(IWICBitmapDecoder *iface, IWICPalette *palette)
1168 {
1169     GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
1170     WICColor colors[256];
1171     ColorMapObject *cm;
1172     int i, trans;
1173     ExtensionBlock *eb;
1174
1175     TRACE("(%p,%p)\n", iface, palette);
1176
1177     cm = This->gif->SColorMap;
1178     if (!cm) return WINCODEC_ERR_FRAMEMISSING;
1179
1180     if (cm->ColorCount > 256)
1181     {
1182         ERR("GIF contains invalid number of colors: %d\n", cm->ColorCount);
1183         return E_FAIL;
1184     }
1185
1186     for (i = 0; i < cm->ColorCount; i++)
1187     {
1188         colors[i] = 0xff000000 | /* alpha */
1189                     cm->Colors[i].Red << 16 |
1190                     cm->Colors[i].Green << 8 |
1191                     cm->Colors[i].Blue;
1192     }
1193
1194     /* look for the transparent color extension */
1195     for (i = 0; i < This->gif->SavedImages[This->current_frame].Extensions.ExtensionBlockCount; i++)
1196     {
1197         eb = This->gif->SavedImages[This->current_frame].Extensions.ExtensionBlocks + i;
1198         if (eb->Function == GRAPHICS_EXT_FUNC_CODE && eb->ByteCount == 8)
1199         {
1200             if (eb->Bytes[3] & 1)
1201             {
1202                 trans = (unsigned char)eb->Bytes[6];
1203                 colors[trans] &= 0xffffff; /* set alpha to 0 */
1204                 break;
1205             }
1206         }
1207     }
1208
1209     return IWICPalette_InitializeCustom(palette, colors, cm->ColorCount);
1210 }
1211
1212 static HRESULT WINAPI GifDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface,
1213     IWICMetadataQueryReader **ppIMetadataQueryReader)
1214 {
1215     TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader);
1216     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1217 }
1218
1219 static HRESULT WINAPI GifDecoder_GetPreview(IWICBitmapDecoder *iface,
1220     IWICBitmapSource **ppIBitmapSource)
1221 {
1222     TRACE("(%p,%p)\n", iface, ppIBitmapSource);
1223     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1224 }
1225
1226 static HRESULT WINAPI GifDecoder_GetColorContexts(IWICBitmapDecoder *iface,
1227     UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
1228 {
1229     TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount);
1230     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1231 }
1232
1233 static HRESULT WINAPI GifDecoder_GetThumbnail(IWICBitmapDecoder *iface,
1234     IWICBitmapSource **ppIThumbnail)
1235 {
1236     TRACE("(%p,%p)\n", iface, ppIThumbnail);
1237     return WINCODEC_ERR_CODECNOTHUMBNAIL;
1238 }
1239
1240 static HRESULT WINAPI GifDecoder_GetFrameCount(IWICBitmapDecoder *iface,
1241     UINT *pCount)
1242 {
1243     GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
1244     TRACE("(%p,%p)\n", iface, pCount);
1245
1246     if (!This->initialized) return WINCODEC_ERR_NOTINITIALIZED;
1247
1248     *pCount = This->gif->ImageCount;
1249
1250     TRACE("<- %u\n", *pCount);
1251
1252     return S_OK;
1253 }
1254
1255 static HRESULT WINAPI GifDecoder_GetFrame(IWICBitmapDecoder *iface,
1256     UINT index, IWICBitmapFrameDecode **ppIBitmapFrame)
1257 {
1258     GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
1259     GifFrameDecode *result;
1260     TRACE("(%p,%u,%p)\n", iface, index, ppIBitmapFrame);
1261
1262     if (!This->initialized) return WINCODEC_ERR_NOTINITIALIZED;
1263
1264     if (index >= This->gif->ImageCount) return E_INVALIDARG;
1265
1266     result = HeapAlloc(GetProcessHeap(), 0, sizeof(GifFrameDecode));
1267     if (!result) return E_OUTOFMEMORY;
1268
1269     result->IWICBitmapFrameDecode_iface.lpVtbl = &GifFrameDecode_Vtbl;
1270     result->IWICMetadataBlockReader_iface.lpVtbl = &GifFrameDecode_BlockVtbl;
1271     result->ref = 1;
1272     result->frame = &This->gif->SavedImages[index];
1273     IWICBitmapDecoder_AddRef(iface);
1274     result->parent = This;
1275     This->current_frame = index;
1276
1277     *ppIBitmapFrame = &result->IWICBitmapFrameDecode_iface;
1278
1279     return S_OK;
1280 }
1281
1282 static const IWICBitmapDecoderVtbl GifDecoder_Vtbl = {
1283     GifDecoder_QueryInterface,
1284     GifDecoder_AddRef,
1285     GifDecoder_Release,
1286     GifDecoder_QueryCapability,
1287     GifDecoder_Initialize,
1288     GifDecoder_GetContainerFormat,
1289     GifDecoder_GetDecoderInfo,
1290     GifDecoder_CopyPalette,
1291     GifDecoder_GetMetadataQueryReader,
1292     GifDecoder_GetPreview,
1293     GifDecoder_GetColorContexts,
1294     GifDecoder_GetThumbnail,
1295     GifDecoder_GetFrameCount,
1296     GifDecoder_GetFrame
1297 };
1298
1299 static HRESULT WINAPI GifDecoder_Block_QueryInterface(IWICMetadataBlockReader *iface,
1300     REFIID iid, void **ppv)
1301 {
1302     GifDecoder *This = impl_from_IWICMetadataBlockReader(iface);
1303     return IWICBitmapDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv);
1304 }
1305
1306 static ULONG WINAPI GifDecoder_Block_AddRef(IWICMetadataBlockReader *iface)
1307 {
1308     GifDecoder *This = impl_from_IWICMetadataBlockReader(iface);
1309     return IWICBitmapDecoder_AddRef(&This->IWICBitmapDecoder_iface);
1310 }
1311
1312 static ULONG WINAPI GifDecoder_Block_Release(IWICMetadataBlockReader *iface)
1313 {
1314     GifDecoder *This = impl_from_IWICMetadataBlockReader(iface);
1315     return IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface);
1316 }
1317
1318 static HRESULT WINAPI GifDecoder_Block_GetContainerFormat(IWICMetadataBlockReader *iface,
1319     GUID *guid)
1320 {
1321     TRACE("(%p,%p)\n", iface, guid);
1322
1323     if (!guid) return E_INVALIDARG;
1324
1325     *guid = GUID_ContainerFormatGif;
1326     return S_OK;
1327 }
1328
1329 static HRESULT WINAPI GifDecoder_Block_GetCount(IWICMetadataBlockReader *iface,
1330     UINT *count)
1331 {
1332     GifDecoder *This = impl_from_IWICMetadataBlockReader(iface);
1333
1334     TRACE("%p,%p\n", iface, count);
1335
1336     if (!count) return E_INVALIDARG;
1337
1338     *count = This->gif->Extensions.ExtensionBlockCount + 1;
1339     return S_OK;
1340 }
1341
1342 static HRESULT WINAPI GifDecoder_Block_GetReaderByIndex(IWICMetadataBlockReader *iface,
1343     UINT index, IWICMetadataReader **reader)
1344 {
1345     GifDecoder *This = impl_from_IWICMetadataBlockReader(iface);
1346     int i;
1347
1348     TRACE("(%p,%u,%p)\n", iface, index, reader);
1349
1350     if (!reader) return E_INVALIDARG;
1351
1352     if (index == 0)
1353         return create_metadata_reader(&This->LSD_data, sizeof(This->LSD_data),
1354                                       &CLSID_WICLSDMetadataReader, reader);
1355
1356     for (i = 0; i < This->gif->Extensions.ExtensionBlockCount; i++)
1357     {
1358         const CLSID *clsid;
1359
1360         if (index != i + 1) continue;
1361
1362         if (This->gif->Extensions.ExtensionBlocks[i].Function == APPLICATION_EXT_FUNC_CODE)
1363             clsid = &CLSID_WICAPEMetadataReader;
1364         else if (This->gif->Extensions.ExtensionBlocks[i].Function == COMMENT_EXT_FUNC_CODE)
1365             clsid = &CLSID_WICGifCommentMetadataReader;
1366         else
1367             clsid = &CLSID_WICUnknownMetadataReader;
1368
1369         return create_metadata_reader(This->gif->Extensions.ExtensionBlocks[i].Bytes,
1370                                       This->gif->Extensions.ExtensionBlocks[i].ByteCount,
1371                                       clsid, reader);
1372     }
1373
1374     return E_INVALIDARG;
1375 }
1376
1377 static HRESULT WINAPI GifDecoder_Block_GetEnumerator(IWICMetadataBlockReader *iface,
1378     IEnumUnknown **enumerator)
1379 {
1380     FIXME("(%p,%p): stub\n", iface, enumerator);
1381     return E_NOTIMPL;
1382 }
1383
1384 static const IWICMetadataBlockReaderVtbl GifDecoder_BlockVtbl =
1385 {
1386     GifDecoder_Block_QueryInterface,
1387     GifDecoder_Block_AddRef,
1388     GifDecoder_Block_Release,
1389     GifDecoder_Block_GetContainerFormat,
1390     GifDecoder_Block_GetCount,
1391     GifDecoder_Block_GetReaderByIndex,
1392     GifDecoder_Block_GetEnumerator
1393 };
1394
1395 HRESULT GifDecoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
1396 {
1397     GifDecoder *This;
1398     HRESULT ret;
1399
1400     TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv);
1401
1402     *ppv = NULL;
1403
1404     if (pUnkOuter) return CLASS_E_NOAGGREGATION;
1405
1406     This = HeapAlloc(GetProcessHeap(), 0, sizeof(GifDecoder));
1407     if (!This) return E_OUTOFMEMORY;
1408
1409     This->IWICBitmapDecoder_iface.lpVtbl = &GifDecoder_Vtbl;
1410     This->IWICMetadataBlockReader_iface.lpVtbl = &GifDecoder_BlockVtbl;
1411     This->ref = 1;
1412     This->initialized = FALSE;
1413     This->gif = NULL;
1414     This->current_frame = 0;
1415     InitializeCriticalSection(&This->lock);
1416     This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": GifDecoder.lock");
1417
1418     ret = IWICBitmapDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv);
1419     IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface);
1420
1421     return ret;
1422 }