Fix signature of SHLWAPI_334 as its string parameter really is an
[wine] / dlls / msvideo / drawdib.c
1 /*
2  * Copyright 2000 Bradley Baetz
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  *
18  * FIXME: Some flags are ignored
19  *
20  * Handle palettes
21  */
22
23 #include <string.h>
24 #include "msvideo_private.h"
25
26 #include "wingdi.h"
27 #include "winuser.h"
28
29 #include "wine/debug.h"
30
31 WINE_DEFAULT_DEBUG_CHANNEL(msvideo);
32
33 typedef struct tagWINE_HDD {
34     HDC                 hdc;
35     INT                 dxDst;
36     INT                 dyDst;
37     LPBITMAPINFOHEADER  lpbi;
38     INT                 dxSrc;
39     INT                 dySrc;
40     HPALETTE            hpal;           /* Palette to use for the DIB */
41     BOOL                begun;          /* DrawDibBegin has been called */
42     LPBITMAPINFOHEADER  lpbiOut;        /* Output format */
43     HIC                 hic;            /* HIC for decompression */
44     HDC                 hMemDC;         /* DC for buffering */
45     HBITMAP             hOldDib;        /* Original Dib */
46     HBITMAP             hDib;           /* DibSection */
47     LPVOID              lpvbits;        /* Buffer for holding decompressed dib */
48     HDRAWDIB            hSelf;
49     struct tagWINE_HDD* next;
50 } WINE_HDD;
51
52 int num_colours(LPBITMAPINFOHEADER lpbi)
53 {
54         if(lpbi->biClrUsed)
55                 return lpbi->biClrUsed;
56         if(lpbi->biBitCount<=8)
57                 return 1<<lpbi->biBitCount;
58         return 0;
59 }
60
61 static WINE_HDD*        HDD_FirstHdd /* = NULL */;
62
63 static WINE_HDD*       MSVIDEO_GetHddPtr(HDRAWDIB hd)
64 {
65     WINE_HDD*   hdd;
66
67     for (hdd = HDD_FirstHdd; hdd != NULL && hdd->hSelf != hdd; hdd = hdd->next);
68     return hdd;
69 }
70
71 static DWORD HDD_HandleRef = 1;
72
73 /***********************************************************************
74  *              DrawDibOpen             [MSVFW32.@]
75  */
76 HDRAWDIB VFWAPI DrawDibOpen(void) 
77 {
78     WINE_HDD*   whdd;
79
80     TRACE("(void)\n");
81         
82     whdd = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WINE_HDD));
83     TRACE("=> %p\n", whdd);
84
85     while (MSVIDEO_GetHddPtr((HDRAWDIB)HDD_HandleRef) != NULL) HDD_HandleRef++;
86     whdd->hSelf = (HDRAWDIB)HDD_HandleRef++;
87
88     whdd->next = HDD_FirstHdd;
89     HDD_FirstHdd = whdd;
90
91     return whdd->hSelf;
92 }
93
94 /***********************************************************************
95  *              DrawDibClose            [MSVFW32.@]
96  */
97 BOOL VFWAPI DrawDibClose(HDRAWDIB hdd) 
98 {
99     WINE_HDD* whdd = MSVIDEO_GetHddPtr(hdd);
100
101     TRACE("(%p)\n", hdd);
102
103     if (!whdd) return FALSE;
104
105     if (whdd->begun) DrawDibEnd(hdd);
106
107     HeapFree(GetProcessHeap(), 0, whdd);
108
109     return TRUE;
110 }
111
112 /***********************************************************************
113  *              DrawDibEnd              [MSVFW32.@]
114  */
115 BOOL VFWAPI DrawDibEnd(HDRAWDIB hdd) 
116 {
117     BOOL ret = TRUE;
118     WINE_HDD *whdd = MSVIDEO_GetHddPtr(hdd);
119
120     TRACE("(%p)\n", hdd);
121
122     whdd->hpal = 0; /* Do not free this */
123     whdd->hdc = 0;
124     if (whdd->lpbi) 
125     {
126         HeapFree(GetProcessHeap(), 0, whdd->lpbi);
127         whdd->lpbi = NULL;
128     }
129     if (whdd->lpbiOut) 
130     {
131         HeapFree(GetProcessHeap(), 0, whdd->lpbiOut);
132         whdd->lpbiOut = NULL;
133     }
134
135     whdd->begun = FALSE;
136
137     /*if (whdd->lpvbits)
138       HeapFree(GetProcessHeap(), 0, whdd->lpvbuf);*/
139
140     if (whdd->hMemDC) 
141     {
142         SelectObject(whdd->hMemDC, whdd->hOldDib);
143         DeleteDC(whdd->hMemDC);
144         whdd->hMemDC = 0;
145     }
146
147     if (whdd->hDib) DeleteObject(whdd->hDib);
148     whdd->hDib = 0;
149
150     if (whdd->hic) 
151     {
152         ICDecompressEnd(whdd->hic);
153         ICClose(whdd->hic);
154         whdd->hic = 0;
155     }
156
157     whdd->lpvbits = NULL;
158
159     return ret;
160 }
161
162 /***********************************************************************
163  *              DrawDibBegin            [MSVFW32.@]
164  */
165 BOOL VFWAPI DrawDibBegin(HDRAWDIB hdd,
166                          HDC      hdc,
167                          INT      dxDst,
168                          INT      dyDst,
169                          LPBITMAPINFOHEADER lpbi,
170                          INT      dxSrc,
171                          INT      dySrc,
172                          UINT     wFlags) 
173 {
174     BOOL ret = TRUE;
175     WINE_HDD *whdd;
176
177     TRACE("(%p,%p,%d,%d,%p,%d,%d,0x%08lx)\n",
178           hdd, hdc, dxDst, dyDst, lpbi, dxSrc, dySrc, (DWORD)wFlags);
179
180     TRACE("lpbi: %ld,%ld/%ld,%d,%d,%ld,%ld,%ld,%ld,%ld,%ld\n",
181           lpbi->biSize, lpbi->biWidth, lpbi->biHeight, lpbi->biPlanes,
182           lpbi->biBitCount, lpbi->biCompression, lpbi->biSizeImage,
183           lpbi->biXPelsPerMeter, lpbi->biYPelsPerMeter, lpbi->biClrUsed,
184           lpbi->biClrImportant);
185
186     if (wFlags & ~(DDF_BUFFER))
187         FIXME("wFlags == 0x%08x not handled\n", wFlags & ~(DDF_BUFFER));
188
189     whdd = MSVIDEO_GetHddPtr(hdd);
190     if (!whdd) return FALSE;
191
192     if (whdd->begun) DrawDibEnd(hdd);
193
194     if (lpbi->biCompression) 
195     {
196         DWORD size = 0;
197
198         whdd->hic = ICOpen(ICTYPE_VIDEO, lpbi->biCompression, ICMODE_DECOMPRESS);
199         if (!whdd->hic) 
200         {
201             WARN("Could not open IC. biCompression == 0x%08lx\n", lpbi->biCompression);
202             ret = FALSE;
203         }
204
205         if (ret) 
206         {
207             size = ICDecompressGetFormat(whdd->hic, lpbi, NULL);
208             if (size == ICERR_UNSUPPORTED) 
209             {
210                 WARN("Codec doesn't support GetFormat, giving up.\n");
211                 ret = FALSE;
212             }
213         }
214
215         if (ret) 
216         {
217             whdd->lpbiOut = HeapAlloc(GetProcessHeap(), 0, size);
218
219             if (ICDecompressGetFormat(whdd->hic, lpbi, whdd->lpbiOut) != ICERR_OK)
220                 ret = FALSE;
221         }
222
223         if (ret) 
224         {
225             /* FIXME: Use Ex functions if available? */
226             if (ICDecompressBegin(whdd->hic, lpbi, whdd->lpbiOut) != ICERR_OK)
227                 ret = FALSE;
228             
229             TRACE("biSizeImage == %ld\n", whdd->lpbiOut->biSizeImage);
230             TRACE("biCompression == %ld\n", whdd->lpbiOut->biCompression);
231             TRACE("biBitCount == %d\n", whdd->lpbiOut->biBitCount);
232         }
233     }
234     else 
235     {
236         DWORD dwSize;
237         /* No compression */
238         TRACE("Not compressed!\n");
239         dwSize = lpbi->biSize + num_colours(lpbi)*sizeof(RGBQUAD);
240         whdd->lpbiOut = HeapAlloc(GetProcessHeap(), 0, dwSize);
241         memcpy(whdd->lpbiOut, lpbi, dwSize);
242     }
243
244     if (ret) 
245     {
246         /*whdd->lpvbuf = HeapAlloc(GetProcessHeap(), 0, whdd->lpbiOut->biSizeImage);*/
247
248         whdd->hMemDC = CreateCompatibleDC(hdc);
249         TRACE("Creating: %ld, %p\n", whdd->lpbiOut->biSize, whdd->lpvbits);
250         whdd->hDib = CreateDIBSection(whdd->hMemDC, (BITMAPINFO *)whdd->lpbiOut, DIB_RGB_COLORS, &(whdd->lpvbits), 0, 0);
251         if (!whdd->hDib) 
252         {
253             TRACE("Error: %ld\n", GetLastError());
254         }
255         TRACE("Created: %p,%p\n", whdd->hDib, whdd->lpvbits);
256         whdd->hOldDib = SelectObject(whdd->hMemDC, whdd->hDib);
257     }
258
259     if (ret) 
260     {
261         whdd->hdc = hdc;
262         whdd->dxDst = dxDst;
263         whdd->dyDst = dyDst;
264         whdd->lpbi = HeapAlloc(GetProcessHeap(), 0, lpbi->biSize);
265         memcpy(whdd->lpbi, lpbi, lpbi->biSize);
266         whdd->dxSrc = dxSrc;
267         whdd->dySrc = dySrc;
268         whdd->begun = TRUE;
269         whdd->hpal = 0;
270     } 
271     else 
272     {
273         if (whdd->hic)
274             ICClose(whdd->hic);
275         if (whdd->lpbiOut) 
276         {
277             HeapFree(GetProcessHeap(), 0, whdd->lpbiOut);
278             whdd->lpbiOut = NULL;
279         }
280     }
281
282     return ret;
283 }
284
285 /**********************************************************************
286  *              DrawDibDraw             [MSVFW32.@]
287  */
288 BOOL VFWAPI DrawDibDraw(HDRAWDIB hdd, HDC hdc,
289                         INT xDst, INT yDst, INT dxDst, INT dyDst,
290                         LPBITMAPINFOHEADER lpbi,
291                         LPVOID lpBits,
292                         INT xSrc, INT ySrc, INT dxSrc, INT dySrc,
293                         UINT wFlags)
294 {
295     WINE_HDD *whdd;
296     BOOL ret = TRUE;
297
298     TRACE("(%p,%p,%d,%d,%d,%d,%p,%p,%d,%d,%d,%d,0x%08lx)\n",
299           hdd, hdc, xDst, yDst, dxDst, dyDst, lpbi, lpBits, xSrc, ySrc, dxSrc, dySrc, (DWORD)wFlags);
300
301     whdd = MSVIDEO_GetHddPtr(hdd);
302     if (whdd) return FALSE;
303
304     if (wFlags & ~(DDF_SAME_HDC | DDF_SAME_DRAW | DDF_NOTKEYFRAME | DDF_UPDATE | DDF_DONTDRAW))
305         FIXME("wFlags == 0x%08lx not handled\n", (DWORD)wFlags);
306
307     if (!lpBits) 
308     {
309         /* Undocumented? */
310         lpBits = (LPSTR)lpbi + (WORD)(lpbi->biSize) + (WORD)(num_colours(lpbi)*sizeof(RGBQUAD));
311     }
312
313
314 #define CHANGED(x) (whdd->x != x)
315
316     if ((!whdd->begun) || 
317         (!(wFlags & DDF_SAME_HDC) && CHANGED(hdc)) || 
318         (!(wFlags & DDF_SAME_DRAW) && (CHANGED(lpbi) || CHANGED(dxSrc) || CHANGED(dySrc) || CHANGED(dxDst) || CHANGED(dyDst)))) 
319     {
320         TRACE("Something changed!\n");
321         ret = DrawDibBegin(hdd, hdc, dxDst, dyDst, lpbi, dxSrc, dySrc, 0);
322     }
323
324 #undef CHANGED
325
326     if ((dxDst == -1) && (dyDst == -1)) 
327     {
328         dxDst = dxSrc;
329         dyDst = dySrc;
330     }
331
332     if (!(wFlags & DDF_UPDATE)) 
333     {
334         /* biSizeImage may be set to 0 for BI_RGB (uncompressed) bitmaps */
335         if ((lpbi->biCompression == BI_RGB) && (lpbi->biSizeImage == 0))
336             lpbi->biSizeImage = ((lpbi->biWidth * lpbi->biBitCount + 31) / 32) * 4 * lpbi->biHeight;
337
338         if (lpbi->biCompression) 
339         {
340             DWORD flags = 0;
341
342             TRACE("Compression == 0x%08lx\n", lpbi->biCompression);
343
344             if (wFlags & DDF_NOTKEYFRAME)
345                 flags |= ICDECOMPRESS_NOTKEYFRAME;
346
347             ICDecompress(whdd->hic, flags, lpbi, lpBits, whdd->lpbiOut, whdd->lpvbits);
348         }
349         else
350         {
351             memcpy(whdd->lpvbits, lpBits, lpbi->biSizeImage);
352         }
353     }
354     if (!(wFlags & DDF_DONTDRAW) && whdd->hpal)
355         SelectPalette(hdc, whdd->hpal, FALSE);
356
357     if (!(StretchBlt(whdd->hdc, xDst, yDst, dxDst, dyDst, whdd->hMemDC, xSrc, ySrc, dxSrc, dySrc, SRCCOPY)))
358         ret = FALSE;
359     
360     return ret;
361 }
362
363 /*************************************************************************
364  *              DrawDibStart            [MSVFW32.@]
365  */
366 BOOL VFWAPI DrawDibStart(HDRAWDIB hdd, DWORD rate) {
367         FIXME("(%p, %ld), stub\n", hdd, rate);
368         return TRUE;
369 }
370
371 /*************************************************************************
372  *              DrawDibStop             [MSVFW32.@]
373  */
374 BOOL VFWAPI DrawDibStop(HDRAWDIB hdd) {
375         FIXME("(%p), stub\n", hdd);
376         return TRUE;
377 }
378
379 /***********************************************************************
380  *              DrawDibSetPalette       [MSVFW32.@]
381  */
382 BOOL VFWAPI DrawDibSetPalette(HDRAWDIB hdd, HPALETTE hpal) 
383 {
384     WINE_HDD *whdd;
385
386     TRACE("(%p, %p)\n", hdd, hpal);
387
388     whdd = MSVIDEO_GetHddPtr(hdd);
389     if (!whdd) return FALSE;
390
391     whdd->hpal = hpal;
392
393     if (whdd->begun) 
394     {
395         SelectPalette(whdd->hdc, hpal, 0);
396         RealizePalette(whdd->hdc);
397     }
398
399     return TRUE;
400 }
401
402 /***********************************************************************
403  *              DrawDibGetPalette       [MSVFW32.@]
404  */
405 HPALETTE VFWAPI DrawDibGetPalette(HDRAWDIB hdd) 
406 {
407     WINE_HDD *whdd;
408
409     TRACE("(%p)\n", hdd);
410
411     whdd = MSVIDEO_GetHddPtr(hdd);
412     if (!whdd) return FALSE;
413
414     return whdd->hpal;
415 }
416
417 /***********************************************************************
418  *              DrawDibRealize          [MSVFW32.@]
419  */
420 UINT VFWAPI DrawDibRealize(HDRAWDIB hdd, HDC hdc, BOOL fBackground) 
421 {
422     WINE_HDD *whdd;
423     HPALETTE oldPal;
424     UINT ret = 0;
425
426     FIXME("(%p, %p, %d), stub\n", hdd, hdc, fBackground);
427
428     whdd = MSVIDEO_GetHddPtr(hdd);
429     if (!whdd) return FALSE;
430
431     if (!whdd || !(whdd->begun)) 
432     {
433         ret = 0;
434         goto out;
435     }
436
437     if (!whdd->hpal)
438         whdd->hpal = CreateHalftonePalette(hdc);
439
440     oldPal = SelectPalette(hdc, whdd->hpal, fBackground);
441     ret = RealizePalette(hdc);
442
443  out:
444     TRACE("=> %u\n", ret);
445     return ret;
446 }