Encode/decode certs, with tests.
[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 static int num_colours(const 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 != hd; 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     WINE_HDD** p;
101
102     TRACE("(%p)\n", hdd);
103
104     if (!whdd) return FALSE;
105
106     if (whdd->begun) DrawDibEnd(hdd);
107
108     for (p = &HDD_FirstHdd; *p != NULL; p = &((*p)->next))
109     {
110         if (*p == whdd)
111         {
112             *p = whdd->next;
113             break;
114         }
115     }
116
117     HeapFree(GetProcessHeap(), 0, whdd);
118
119     return TRUE;
120 }
121
122 /***********************************************************************
123  *              DrawDibEnd              [MSVFW32.@]
124  */
125 BOOL VFWAPI DrawDibEnd(HDRAWDIB hdd) 
126 {
127     BOOL ret = TRUE;
128     WINE_HDD *whdd = MSVIDEO_GetHddPtr(hdd);
129
130     TRACE("(%p)\n", hdd);
131
132     whdd->hpal = 0; /* Do not free this */
133     whdd->hdc = 0;
134     HeapFree(GetProcessHeap(), 0, whdd->lpbi);
135     whdd->lpbi = NULL;
136     HeapFree(GetProcessHeap(), 0, whdd->lpbiOut);
137     whdd->lpbiOut = NULL;
138
139     whdd->begun = FALSE;
140
141     /*if (whdd->lpvbits)
142       HeapFree(GetProcessHeap(), 0, whdd->lpvbuf);*/
143
144     if (whdd->hMemDC) 
145     {
146         SelectObject(whdd->hMemDC, whdd->hOldDib);
147         DeleteDC(whdd->hMemDC);
148         whdd->hMemDC = 0;
149     }
150
151     if (whdd->hDib) DeleteObject(whdd->hDib);
152     whdd->hDib = 0;
153
154     if (whdd->hic) 
155     {
156         ICDecompressEnd(whdd->hic);
157         ICClose(whdd->hic);
158         whdd->hic = 0;
159     }
160
161     whdd->lpvbits = NULL;
162
163     return ret;
164 }
165
166 /***********************************************************************
167  *              DrawDibBegin            [MSVFW32.@]
168  */
169 BOOL VFWAPI DrawDibBegin(HDRAWDIB hdd,
170                          HDC      hdc,
171                          INT      dxDst,
172                          INT      dyDst,
173                          LPBITMAPINFOHEADER lpbi,
174                          INT      dxSrc,
175                          INT      dySrc,
176                          UINT     wFlags) 
177 {
178     BOOL ret = TRUE;
179     WINE_HDD *whdd;
180
181     TRACE("(%p,%p,%d,%d,%p,%d,%d,0x%08lx)\n",
182           hdd, hdc, dxDst, dyDst, lpbi, dxSrc, dySrc, (DWORD)wFlags);
183
184     TRACE("lpbi: %ld,%ld/%ld,%d,%d,%ld,%ld,%ld,%ld,%ld,%ld\n",
185           lpbi->biSize, lpbi->biWidth, lpbi->biHeight, lpbi->biPlanes,
186           lpbi->biBitCount, lpbi->biCompression, lpbi->biSizeImage,
187           lpbi->biXPelsPerMeter, lpbi->biYPelsPerMeter, lpbi->biClrUsed,
188           lpbi->biClrImportant);
189
190     if (wFlags & ~(DDF_BUFFER))
191         FIXME("wFlags == 0x%08x not handled\n", wFlags & ~(DDF_BUFFER));
192
193     whdd = MSVIDEO_GetHddPtr(hdd);
194     if (!whdd) return FALSE;
195
196     if (whdd->begun) DrawDibEnd(hdd);
197
198     if (lpbi->biCompression) 
199     {
200         DWORD size = 0;
201
202         whdd->hic = ICOpen(ICTYPE_VIDEO, lpbi->biCompression, ICMODE_DECOMPRESS);
203         if (!whdd->hic) 
204         {
205             WARN("Could not open IC. biCompression == 0x%08lx\n", lpbi->biCompression);
206             ret = FALSE;
207         }
208
209         if (ret) 
210         {
211             size = ICDecompressGetFormat(whdd->hic, lpbi, NULL);
212             if (size == ICERR_UNSUPPORTED) 
213             {
214                 WARN("Codec doesn't support GetFormat, giving up.\n");
215                 ret = FALSE;
216             }
217         }
218
219         if (ret) 
220         {
221             whdd->lpbiOut = HeapAlloc(GetProcessHeap(), 0, size);
222
223             if (ICDecompressGetFormat(whdd->hic, lpbi, whdd->lpbiOut) != ICERR_OK)
224                 ret = FALSE;
225         }
226
227         if (ret) 
228         {
229             /* FIXME: Use Ex functions if available? */
230             if (ICDecompressBegin(whdd->hic, lpbi, whdd->lpbiOut) != ICERR_OK)
231                 ret = FALSE;
232             
233             TRACE("biSizeImage == %ld\n", whdd->lpbiOut->biSizeImage);
234             TRACE("biCompression == %ld\n", whdd->lpbiOut->biCompression);
235             TRACE("biBitCount == %d\n", whdd->lpbiOut->biBitCount);
236         }
237     }
238     else 
239     {
240         DWORD dwSize;
241         /* No compression */
242         TRACE("Not compressed!\n");
243         dwSize = lpbi->biSize + num_colours(lpbi)*sizeof(RGBQUAD);
244         whdd->lpbiOut = HeapAlloc(GetProcessHeap(), 0, dwSize);
245         memcpy(whdd->lpbiOut, lpbi, dwSize);
246     }
247
248     if (ret) 
249     {
250         /*whdd->lpvbuf = HeapAlloc(GetProcessHeap(), 0, whdd->lpbiOut->biSizeImage);*/
251
252         whdd->hMemDC = CreateCompatibleDC(hdc);
253         TRACE("Creating: %ld, %p\n", whdd->lpbiOut->biSize, whdd->lpvbits);
254         whdd->hDib = CreateDIBSection(whdd->hMemDC, (BITMAPINFO *)whdd->lpbiOut, DIB_RGB_COLORS, &(whdd->lpvbits), 0, 0);
255         if (whdd->hDib) 
256         {
257             TRACE("Created: %p,%p\n", whdd->hDib, whdd->lpvbits);
258         }
259         else
260         {
261             ret = FALSE;
262             TRACE("Error: %ld\n", GetLastError());
263         }
264         whdd->hOldDib = SelectObject(whdd->hMemDC, whdd->hDib);
265     }
266
267     if (ret) 
268     {
269         whdd->hdc = hdc;
270         whdd->dxDst = dxDst;
271         whdd->dyDst = dyDst;
272         whdd->lpbi = HeapAlloc(GetProcessHeap(), 0, lpbi->biSize);
273         memcpy(whdd->lpbi, lpbi, lpbi->biSize);
274         whdd->dxSrc = dxSrc;
275         whdd->dySrc = dySrc;
276         whdd->begun = TRUE;
277         whdd->hpal = 0;
278     } 
279     else 
280     {
281         if (whdd->hic)
282             ICClose(whdd->hic);
283         HeapFree(GetProcessHeap(), 0, whdd->lpbiOut);
284         whdd->lpbiOut = NULL;
285     }
286
287     return ret;
288 }
289
290 /**********************************************************************
291  *              DrawDibDraw             [MSVFW32.@]
292  */
293 BOOL VFWAPI DrawDibDraw(HDRAWDIB hdd, HDC hdc,
294                         INT xDst, INT yDst, INT dxDst, INT dyDst,
295                         LPBITMAPINFOHEADER lpbi,
296                         LPVOID lpBits,
297                         INT xSrc, INT ySrc, INT dxSrc, INT dySrc,
298                         UINT wFlags)
299 {
300     WINE_HDD *whdd;
301     BOOL ret = TRUE;
302
303     TRACE("(%p,%p,%d,%d,%d,%d,%p,%p,%d,%d,%d,%d,0x%08lx)\n",
304           hdd, hdc, xDst, yDst, dxDst, dyDst, lpbi, lpBits, xSrc, ySrc, dxSrc, dySrc, (DWORD)wFlags);
305
306     whdd = MSVIDEO_GetHddPtr(hdd);
307     if (!whdd) return FALSE;
308
309     TRACE("whdd=%p\n", whdd);
310
311     if (wFlags & ~(DDF_SAME_HDC | DDF_SAME_DRAW | DDF_NOTKEYFRAME | DDF_UPDATE | DDF_DONTDRAW | DDF_BACKGROUNDPAL))
312         FIXME("wFlags == 0x%08lx not handled\n", (DWORD)wFlags);
313
314     if (!lpBits) 
315     {
316         /* Undocumented? */
317         lpBits = (LPSTR)lpbi + (WORD)(lpbi->biSize) + (WORD)(num_colours(lpbi)*sizeof(RGBQUAD));
318     }
319
320
321 #define CHANGED(x) (whdd->x != x)
322
323     if ((!whdd->begun) || 
324         (!(wFlags & DDF_SAME_HDC) && CHANGED(hdc)) || 
325         (!(wFlags & DDF_SAME_DRAW) && (CHANGED(lpbi) || CHANGED(dxSrc) || CHANGED(dySrc) || CHANGED(dxDst) || CHANGED(dyDst)))) 
326     {
327         TRACE("Something changed!\n");
328         ret = DrawDibBegin(hdd, hdc, dxDst, dyDst, lpbi, dxSrc, dySrc, 0);
329     }
330
331 #undef CHANGED
332
333     if ((dxDst == -1) && (dyDst == -1)) 
334     {
335         dxDst = dxSrc;
336         dyDst = dySrc;
337     }
338
339     if (!(wFlags & DDF_UPDATE)) 
340     {
341         DWORD biSizeImage = lpbi->biSizeImage;
342
343         /* biSizeImage may be set to 0 for BI_RGB (uncompressed) bitmaps */
344         if ((lpbi->biCompression == BI_RGB) && (biSizeImage == 0))
345             biSizeImage = ((lpbi->biWidth * lpbi->biBitCount + 31) / 32) * 4 * lpbi->biHeight;
346
347         if (lpbi->biCompression) 
348         {
349             DWORD flags = 0;
350
351             TRACE("Compression == 0x%08lx\n", lpbi->biCompression);
352
353             if (wFlags & DDF_NOTKEYFRAME)
354                 flags |= ICDECOMPRESS_NOTKEYFRAME;
355
356             ICDecompress(whdd->hic, flags, lpbi, lpBits, whdd->lpbiOut, whdd->lpvbits);
357         }
358         else
359         {
360             memcpy(whdd->lpvbits, lpBits, biSizeImage);
361         }
362     }
363     if (!(wFlags & DDF_DONTDRAW) && whdd->hpal)
364     {
365         if ((wFlags & DDF_BACKGROUNDPAL) && ! (wFlags & DDF_SAME_HDC))
366          SelectPalette(hdc, whdd->hpal, TRUE);
367         else
368          SelectPalette(hdc, whdd->hpal, FALSE);
369     }
370
371     if (!(StretchBlt(whdd->hdc, xDst, yDst, dxDst, dyDst, whdd->hMemDC, xSrc, ySrc, dxSrc, dySrc, SRCCOPY)))
372         ret = FALSE;
373     
374     return ret;
375 }
376
377 /*************************************************************************
378  *              DrawDibStart            [MSVFW32.@]
379  */
380 BOOL VFWAPI DrawDibStart(HDRAWDIB hdd, DWORD rate) {
381         FIXME("(%p, %ld), stub\n", hdd, rate);
382         return TRUE;
383 }
384
385 /*************************************************************************
386  *              DrawDibStop             [MSVFW32.@]
387  */
388 BOOL VFWAPI DrawDibStop(HDRAWDIB hdd) {
389         FIXME("(%p), stub\n", hdd);
390         return TRUE;
391 }
392
393 /***********************************************************************
394  *              DrawDibChangePalette       [MSVFW32.@]
395  */
396 BOOL VFWAPI DrawDibChangePalette(HDRAWDIB hdd, int iStart, int iLen, LPPALETTEENTRY lppe)
397 {
398     FIXME("(%p, 0x%08x, 0x%08x, %p), stub\n", hdd, iStart, iLen, lppe);
399     return TRUE;
400 }
401
402 /***********************************************************************
403  *              DrawDibSetPalette       [MSVFW32.@]
404  */
405 BOOL VFWAPI DrawDibSetPalette(HDRAWDIB hdd, HPALETTE hpal) 
406 {
407     WINE_HDD *whdd;
408
409     TRACE("(%p, %p)\n", hdd, hpal);
410
411     whdd = MSVIDEO_GetHddPtr(hdd);
412     if (!whdd) return FALSE;
413
414     whdd->hpal = hpal;
415
416     if (whdd->begun) 
417     {
418         SelectPalette(whdd->hdc, hpal, 0);
419         RealizePalette(whdd->hdc);
420     }
421
422     return TRUE;
423 }
424
425 /***********************************************************************
426  *              DrawDibGetBuffer       [MSVFW32.@]
427  */
428 LPVOID VFWAPI DrawDibGetBuffer(HDRAWDIB hdd, LPBITMAPINFOHEADER lpbi, DWORD dwSize, DWORD dwFlags)
429 {
430     FIXME("(%p, %p, 0x%08lx, 0x%08lx), stub\n", hdd, lpbi, dwSize, dwFlags);   
431     return NULL;
432 }
433
434 /***********************************************************************
435  *              DrawDibGetPalette       [MSVFW32.@]
436  */
437 HPALETTE VFWAPI DrawDibGetPalette(HDRAWDIB hdd) 
438 {
439     WINE_HDD *whdd;
440
441     TRACE("(%p)\n", hdd);
442
443     whdd = MSVIDEO_GetHddPtr(hdd);
444     if (!whdd) return FALSE;
445
446     return whdd->hpal;
447 }
448
449 /***********************************************************************
450  *              DrawDibRealize          [MSVFW32.@]
451  */
452 UINT VFWAPI DrawDibRealize(HDRAWDIB hdd, HDC hdc, BOOL fBackground) 
453 {
454     WINE_HDD *whdd;
455     HPALETTE oldPal;
456     UINT ret = 0;
457
458     FIXME("(%p, %p, %d), stub\n", hdd, hdc, fBackground);
459
460     whdd = MSVIDEO_GetHddPtr(hdd);
461     if (!whdd) return FALSE;
462
463     if (!whdd || !(whdd->begun)) 
464     {
465         ret = 0;
466         goto out;
467     }
468
469     if (!whdd->hpal)
470         whdd->hpal = CreateHalftonePalette(hdc);
471
472     oldPal = SelectPalette(hdc, whdd->hpal, fBackground);
473     ret = RealizePalette(hdc);
474
475  out:
476     TRACE("=> %u\n", ret);
477     return ret;
478 }
479
480 /***********************************************************************
481  *              DrawDibTime          [MSVFW32.@]
482  */
483 BOOL VFWAPI DrawDibTime(HDRAWDIB hdd, LPDRAWDIBTIME lpddtime)
484 {
485     FIXME("(%p, %p) stub\n", hdd, lpddtime);
486     return FALSE;
487 }
488
489 /***********************************************************************
490  *              DrawDibProfileDisplay          [MSVFW32.@]
491  */
492 DWORD VFWAPI DrawDibProfileDisplay(LPBITMAPINFOHEADER lpbi)
493 {
494     FIXME("(%p) stub\n", lpbi);
495
496     return PD_CAN_DRAW_DIB;
497 }