gdiplus: Fix the linesfilled calculation in GdipMeasureString.
[wine.git] / dlls / windowscodecs / gifformat.c
blob0597b1afbe31c3d30601c8fb6ee7532a25a4dba6
1 /*
2 * Copyright 2009 Vincent Povirk for CodeWeavers
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.
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.
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
19 #include "config.h"
21 #include <stdarg.h>
23 #define COBJMACROS
25 #include "windef.h"
26 #include "winbase.h"
27 #include "objbase.h"
28 #include "wincodec.h"
30 #include "ungif.h"
32 #include "wincodecs_private.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
38 typedef struct {
39 const IWICBitmapDecoderVtbl *lpVtbl;
40 LONG ref;
41 BOOL initialized;
42 GifFileType *gif;
43 } GifDecoder;
45 typedef struct {
46 const IWICBitmapFrameDecodeVtbl *lpVtbl;
47 LONG ref;
48 SavedImage *frame;
49 GifDecoder *parent;
50 } GifFrameDecode;
52 static HRESULT WINAPI GifFrameDecode_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid,
53 void **ppv)
55 GifFrameDecode *This = (GifFrameDecode*)iface;
56 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
58 if (!ppv) return E_INVALIDARG;
60 if (IsEqualIID(&IID_IUnknown, iid) ||
61 IsEqualIID(&IID_IWICBitmapSource, iid) ||
62 IsEqualIID(&IID_IWICBitmapFrameDecode, iid))
64 *ppv = This;
66 else
68 *ppv = NULL;
69 return E_NOINTERFACE;
72 IUnknown_AddRef((IUnknown*)*ppv);
73 return S_OK;
76 static ULONG WINAPI GifFrameDecode_AddRef(IWICBitmapFrameDecode *iface)
78 GifFrameDecode *This = (GifFrameDecode*)iface;
79 ULONG ref = InterlockedIncrement(&This->ref);
81 TRACE("(%p) refcount=%u\n", iface, ref);
83 return ref;
86 static ULONG WINAPI GifFrameDecode_Release(IWICBitmapFrameDecode *iface)
88 GifFrameDecode *This = (GifFrameDecode*)iface;
89 ULONG ref = InterlockedDecrement(&This->ref);
91 TRACE("(%p) refcount=%u\n", iface, ref);
93 if (ref == 0)
95 IUnknown_Release((IUnknown*)This->parent);
96 HeapFree(GetProcessHeap(), 0, This);
99 return ref;
102 static HRESULT WINAPI GifFrameDecode_GetSize(IWICBitmapFrameDecode *iface,
103 UINT *puiWidth, UINT *puiHeight)
105 GifFrameDecode *This = (GifFrameDecode*)iface;
106 TRACE("(%p,%p,%p)\n", iface, puiWidth, puiHeight);
108 *puiWidth = This->frame->ImageDesc.Width;
109 *puiHeight = This->frame->ImageDesc.Height;
111 return S_OK;
114 static HRESULT WINAPI GifFrameDecode_GetPixelFormat(IWICBitmapFrameDecode *iface,
115 WICPixelFormatGUID *pPixelFormat)
117 memcpy(pPixelFormat, &GUID_WICPixelFormat8bppIndexed, sizeof(GUID));
119 return S_OK;
122 static HRESULT WINAPI GifFrameDecode_GetResolution(IWICBitmapFrameDecode *iface,
123 double *pDpiX, double *pDpiY)
125 FIXME("(%p,%p,%p): stub\n", iface, pDpiX, pDpiY);
126 return E_NOTIMPL;
129 static HRESULT WINAPI GifFrameDecode_CopyPalette(IWICBitmapFrameDecode *iface,
130 IWICPalette *pIPalette)
132 GifFrameDecode *This = (GifFrameDecode*)iface;
133 WICColor colors[256];
134 ColorMapObject *cm = This->frame->ImageDesc.ColorMap;
135 int i, trans;
136 ExtensionBlock *eb;
137 TRACE("(%p,%p)\n", iface, pIPalette);
139 if (!cm) cm = This->parent->gif->SColorMap;
141 if (cm->ColorCount > 256)
143 ERR("GIF contains %i colors???\n", cm->ColorCount);
144 return E_FAIL;
147 for (i = 0; i < cm->ColorCount; i++) {
148 colors[i] = 0xff000000| /* alpha */
149 cm->Colors[i].Red << 16|
150 cm->Colors[i].Green << 8|
151 cm->Colors[i].Blue;
154 /* look for the transparent color extension */
155 for (i = 0; i < This->frame->ExtensionBlockCount; ++i) {
156 eb = This->frame->ExtensionBlocks + i;
157 if (eb->Function == 0xF9 && eb->ByteCount == 4) {
158 if ((eb->Bytes[0] & 1) == 1) {
159 trans = (unsigned char)eb->Bytes[3];
160 colors[trans] &= 0xffffff; /* set alpha to 0 */
161 break;
166 IWICPalette_InitializeCustom(pIPalette, colors, cm->ColorCount);
168 return S_OK;
171 static HRESULT copy_interlaced_pixels(const BYTE *srcbuffer,
172 UINT srcwidth, UINT srcheight, INT srcstride, const WICRect *rc,
173 UINT dststride, UINT dstbuffersize, BYTE *dstbuffer)
175 UINT row_offset; /* number of bytes into the source rows where the data starts */
176 const BYTE *src;
177 BYTE *dst;
178 UINT y;
180 if (rc->X < 0 || rc->Y < 0 || rc->X+rc->Width > srcwidth || rc->Y+rc->Height > srcheight)
181 return E_INVALIDARG;
183 if (dststride < rc->Width)
184 return E_INVALIDARG;
186 if ((dststride * rc->Height) > dstbuffersize)
187 return E_INVALIDARG;
189 row_offset = rc->X;
191 dst = dstbuffer;
192 for (y=rc->Y; y-rc->Y < rc->Height; y++)
194 if (y%8 == 0)
195 src = srcbuffer + srcstride * (y/8);
196 else if (y%4 == 0)
197 src = srcbuffer + srcstride * ((srcheight+7)/8 + y/8);
198 else if (y%2 == 0)
199 src = srcbuffer + srcstride * ((srcheight+3)/4 + y/4);
200 else /* y%2 == 1 */
201 src = srcbuffer + srcstride * ((srcheight+1)/2 + y/2);
202 src += row_offset;
203 memcpy(dst, src, rc->Width);
204 dst += dststride;
206 return S_OK;
209 static HRESULT WINAPI GifFrameDecode_CopyPixels(IWICBitmapFrameDecode *iface,
210 const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
212 GifFrameDecode *This = (GifFrameDecode*)iface;
213 TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer);
215 if (This->frame->ImageDesc.Interlace)
217 return copy_interlaced_pixels(This->frame->RasterBits, This->frame->ImageDesc.Width,
218 This->frame->ImageDesc.Height, This->frame->ImageDesc.Width,
219 prc, cbStride, cbBufferSize, pbBuffer);
221 else
223 return copy_pixels(8, This->frame->RasterBits, This->frame->ImageDesc.Width,
224 This->frame->ImageDesc.Height, This->frame->ImageDesc.Width,
225 prc, cbStride, cbBufferSize, pbBuffer);
229 static HRESULT WINAPI GifFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode *iface,
230 IWICMetadataQueryReader **ppIMetadataQueryReader)
232 TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader);
233 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
236 static HRESULT WINAPI GifFrameDecode_GetColorContexts(IWICBitmapFrameDecode *iface,
237 UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
239 TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount);
240 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
243 static HRESULT WINAPI GifFrameDecode_GetThumbnail(IWICBitmapFrameDecode *iface,
244 IWICBitmapSource **ppIThumbnail)
246 TRACE("(%p,%p)\n", iface, ppIThumbnail);
247 return WINCODEC_ERR_CODECNOTHUMBNAIL;
250 static const IWICBitmapFrameDecodeVtbl GifFrameDecode_Vtbl = {
251 GifFrameDecode_QueryInterface,
252 GifFrameDecode_AddRef,
253 GifFrameDecode_Release,
254 GifFrameDecode_GetSize,
255 GifFrameDecode_GetPixelFormat,
256 GifFrameDecode_GetResolution,
257 GifFrameDecode_CopyPalette,
258 GifFrameDecode_CopyPixels,
259 GifFrameDecode_GetMetadataQueryReader,
260 GifFrameDecode_GetColorContexts,
261 GifFrameDecode_GetThumbnail
264 static HRESULT WINAPI GifDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid,
265 void **ppv)
267 GifDecoder *This = (GifDecoder*)iface;
268 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
270 if (!ppv) return E_INVALIDARG;
272 if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IWICBitmapDecoder, iid))
274 *ppv = This;
276 else
278 *ppv = NULL;
279 return E_NOINTERFACE;
282 IUnknown_AddRef((IUnknown*)*ppv);
283 return S_OK;
286 static ULONG WINAPI GifDecoder_AddRef(IWICBitmapDecoder *iface)
288 GifDecoder *This = (GifDecoder*)iface;
289 ULONG ref = InterlockedIncrement(&This->ref);
291 TRACE("(%p) refcount=%u\n", iface, ref);
293 return ref;
296 static ULONG WINAPI GifDecoder_Release(IWICBitmapDecoder *iface)
298 GifDecoder *This = (GifDecoder*)iface;
299 ULONG ref = InterlockedDecrement(&This->ref);
301 TRACE("(%p) refcount=%u\n", iface, ref);
303 if (ref == 0)
305 DGifCloseFile(This->gif);
306 HeapFree(GetProcessHeap(), 0, This);
309 return ref;
312 static HRESULT WINAPI GifDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *pIStream,
313 DWORD *pdwCapability)
315 FIXME("(%p,%p,%p): stub\n", iface, pIStream, pdwCapability);
316 return E_NOTIMPL;
319 static int _gif_inputfunc(GifFileType *gif, GifByteType *data, int len) {
320 IStream *stream = gif->UserData;
321 ULONG bytesread;
322 HRESULT hr;
324 if (!stream)
326 ERR("attempting to read file after initialization\n");
327 return 0;
330 hr = IStream_Read(stream, data, len, &bytesread);
331 if (hr != S_OK) bytesread = 0;
332 return bytesread;
335 static HRESULT WINAPI GifDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream,
336 WICDecodeOptions cacheOptions)
338 GifDecoder *This = (GifDecoder*)iface;
339 LARGE_INTEGER seek;
340 int ret;
342 TRACE("(%p,%p,%x)\n", iface, pIStream, cacheOptions);
344 if (This->initialized || This->gif)
346 WARN("already initialized\n");
347 return WINCODEC_ERR_WRONGSTATE;
350 /* seek to start of stream */
351 seek.QuadPart = 0;
352 IStream_Seek(pIStream, seek, STREAM_SEEK_SET, NULL);
354 /* read all data from the stream */
355 This->gif = DGifOpen((void*)pIStream, _gif_inputfunc);
356 if (!This->gif) return E_FAIL;
358 ret = DGifSlurp(This->gif);
359 if (ret == GIF_ERROR) return E_FAIL;
361 /* make sure we don't use the stream after this method returns */
362 This->gif->UserData = NULL;
364 This->initialized = TRUE;
366 return S_OK;
369 static HRESULT WINAPI GifDecoder_GetContainerFormat(IWICBitmapDecoder *iface,
370 GUID *pguidContainerFormat)
372 memcpy(pguidContainerFormat, &GUID_ContainerFormatGif, sizeof(GUID));
373 return S_OK;
376 static HRESULT WINAPI GifDecoder_GetDecoderInfo(IWICBitmapDecoder *iface,
377 IWICBitmapDecoderInfo **ppIDecoderInfo)
379 HRESULT hr;
380 IWICComponentInfo *compinfo;
382 TRACE("(%p,%p)\n", iface, ppIDecoderInfo);
384 hr = CreateComponentInfo(&CLSID_WICGifDecoder, &compinfo);
385 if (FAILED(hr)) return hr;
387 hr = IWICComponentInfo_QueryInterface(compinfo, &IID_IWICBitmapDecoderInfo,
388 (void**)ppIDecoderInfo);
390 IWICComponentInfo_Release(compinfo);
392 return hr;
395 static HRESULT WINAPI GifDecoder_CopyPalette(IWICBitmapDecoder *iface,
396 IWICPalette *pIPalette)
398 TRACE("(%p,%p)\n", iface, pIPalette);
399 return WINCODEC_ERR_PALETTEUNAVAILABLE;
402 static HRESULT WINAPI GifDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface,
403 IWICMetadataQueryReader **ppIMetadataQueryReader)
405 TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader);
406 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
409 static HRESULT WINAPI GifDecoder_GetPreview(IWICBitmapDecoder *iface,
410 IWICBitmapSource **ppIBitmapSource)
412 TRACE("(%p,%p)\n", iface, ppIBitmapSource);
413 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
416 static HRESULT WINAPI GifDecoder_GetColorContexts(IWICBitmapDecoder *iface,
417 UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
419 TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount);
420 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
423 static HRESULT WINAPI GifDecoder_GetThumbnail(IWICBitmapDecoder *iface,
424 IWICBitmapSource **ppIThumbnail)
426 TRACE("(%p,%p)\n", iface, ppIThumbnail);
427 return WINCODEC_ERR_CODECNOTHUMBNAIL;
430 static HRESULT WINAPI GifDecoder_GetFrameCount(IWICBitmapDecoder *iface,
431 UINT *pCount)
433 GifDecoder *This = (GifDecoder*)iface;
434 TRACE("(%p,%p)\n", iface, pCount);
436 if (!This->initialized) return WINCODEC_ERR_NOTINITIALIZED;
438 *pCount = This->gif->ImageCount;
440 TRACE("<- %u\n", *pCount);
442 return S_OK;
445 static HRESULT WINAPI GifDecoder_GetFrame(IWICBitmapDecoder *iface,
446 UINT index, IWICBitmapFrameDecode **ppIBitmapFrame)
448 GifDecoder *This = (GifDecoder*)iface;
449 GifFrameDecode *result;
450 TRACE("(%p,%u,%p)\n", iface, index, ppIBitmapFrame);
452 if (!This->initialized) return WINCODEC_ERR_NOTINITIALIZED;
454 if (index >= This->gif->ImageCount) return E_INVALIDARG;
456 result = HeapAlloc(GetProcessHeap(), 0, sizeof(GifFrameDecode));
457 if (!result) return E_OUTOFMEMORY;
459 result->lpVtbl = &GifFrameDecode_Vtbl;
460 result->ref = 1;
461 result->frame = &This->gif->SavedImages[index];
462 IWICBitmapDecoder_AddRef(iface);
463 result->parent = This;
465 *ppIBitmapFrame = (IWICBitmapFrameDecode*)result;
467 return S_OK;
470 static const IWICBitmapDecoderVtbl GifDecoder_Vtbl = {
471 GifDecoder_QueryInterface,
472 GifDecoder_AddRef,
473 GifDecoder_Release,
474 GifDecoder_QueryCapability,
475 GifDecoder_Initialize,
476 GifDecoder_GetContainerFormat,
477 GifDecoder_GetDecoderInfo,
478 GifDecoder_CopyPalette,
479 GifDecoder_GetMetadataQueryReader,
480 GifDecoder_GetPreview,
481 GifDecoder_GetColorContexts,
482 GifDecoder_GetThumbnail,
483 GifDecoder_GetFrameCount,
484 GifDecoder_GetFrame
487 HRESULT GifDecoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
489 GifDecoder *This;
490 HRESULT ret;
492 TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv);
494 *ppv = NULL;
496 if (pUnkOuter) return CLASS_E_NOAGGREGATION;
498 This = HeapAlloc(GetProcessHeap(), 0, sizeof(GifDecoder));
499 if (!This) return E_OUTOFMEMORY;
501 This->lpVtbl = &GifDecoder_Vtbl;
502 This->ref = 1;
503 This->initialized = FALSE;
504 This->gif = NULL;
506 ret = IUnknown_QueryInterface((IUnknown*)This, iid, ppv);
507 IUnknown_Release((IUnknown*)This);
509 return ret;