xref: /reactos/dll/win32/msvfw32/drawdib.c (revision d5399189)
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  *
18  * FIXME: Some flags are ignored
19  *
20  * Handle palettes
21  */
22 
23 #include <stdarg.h>
24 #include <stdio.h>
25 #include <string.h>
26 
27 #include "windef.h"
28 #include "winbase.h"
29 #include "wingdi.h"
30 #include "winuser.h"
31 #include "vfw.h"
32 
33 #include "wine/debug.h"
34 
35 WINE_DEFAULT_DEBUG_CHANNEL(msvideo);
36 
37 typedef struct tagWINE_HDD {
38     HDC                 hdc;
39     INT                 dxDst;
40     INT                 dyDst;
41     LPBITMAPINFOHEADER  lpbi;
42     INT                 dxSrc;
43     INT                 dySrc;
44     HPALETTE            hpal;		/* Palette to use for the DIB */
45     BOOL                begun;		/* DrawDibBegin has been called */
46     LPBITMAPINFOHEADER  lpbiOut;	/* Output format */
47     HIC                 hic;		/* HIC for decompression */
48     HDC                 hMemDC;		/* DC for buffering */
49     HBITMAP             hOldDib;	/* Original Dib */
50     HBITMAP             hDib;		/* DibSection */
51     LPVOID              lpvbits;	/* Buffer for holding decompressed dib */
52     HDRAWDIB            hSelf;
53     struct tagWINE_HDD* next;
54 } WINE_HDD;
55 
56 static int num_colours(const BITMAPINFOHEADER *lpbi)
57 {
58 	if(lpbi->biClrUsed)
59 		return lpbi->biClrUsed;
60 	if(lpbi->biBitCount<=8)
61 		return 1<<lpbi->biBitCount;
62 	return 0;
63 }
64 
65 static WINE_HDD*        HDD_FirstHdd /* = NULL */;
66 
67 static WINE_HDD*       MSVIDEO_GetHddPtr(HDRAWDIB hd)
68 {
69     WINE_HDD*   hdd;
70 
71     for (hdd = HDD_FirstHdd; hdd != NULL && hdd->hSelf != hd; hdd = hdd->next);
72     return hdd;
73 }
74 
75 static UINT_PTR HDD_HandleRef = 1;
76 
77 /***********************************************************************
78  *		DrawDibOpen		[MSVFW32.@]
79  */
80 HDRAWDIB VFWAPI DrawDibOpen(void)
81 {
82     WINE_HDD*   whdd;
83 
84     TRACE("(void)\n");
85 
86     whdd = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WINE_HDD));
87     TRACE("=> %p\n", whdd);
88 
89     while (MSVIDEO_GetHddPtr((HDRAWDIB)HDD_HandleRef) != NULL) HDD_HandleRef++;
90     whdd->hSelf = (HDRAWDIB)HDD_HandleRef++;
91 
92     whdd->next = HDD_FirstHdd;
93     HDD_FirstHdd = whdd;
94 
95     return whdd->hSelf;
96 }
97 
98 /***********************************************************************
99  *		DrawDibClose		[MSVFW32.@]
100  */
101 BOOL VFWAPI DrawDibClose(HDRAWDIB hdd)
102 {
103     WINE_HDD* whdd = MSVIDEO_GetHddPtr(hdd);
104     WINE_HDD** p;
105 
106     TRACE("(%p)\n", hdd);
107 
108     if (!whdd) return FALSE;
109 
110     if (whdd->begun) DrawDibEnd(hdd);
111 
112     for (p = &HDD_FirstHdd; *p != NULL; p = &((*p)->next))
113     {
114         if (*p == whdd)
115         {
116             *p = whdd->next;
117             break;
118         }
119     }
120 
121     HeapFree(GetProcessHeap(), 0, whdd);
122 
123     return TRUE;
124 }
125 
126 /***********************************************************************
127  *		DrawDibEnd		[MSVFW32.@]
128  */
129 BOOL VFWAPI DrawDibEnd(HDRAWDIB hdd)
130 {
131     BOOL ret = TRUE;
132     WINE_HDD *whdd = MSVIDEO_GetHddPtr(hdd);
133 
134     TRACE("(%p)\n", hdd);
135 
136     if (!whdd) return FALSE;
137 
138     whdd->hpal = 0; /* Do not free this */
139     whdd->hdc = 0;
140     HeapFree(GetProcessHeap(), 0, whdd->lpbi);
141     whdd->lpbi = NULL;
142     HeapFree(GetProcessHeap(), 0, whdd->lpbiOut);
143     whdd->lpbiOut = NULL;
144 
145     whdd->begun = FALSE;
146 
147     /*if (whdd->lpvbits)
148       HeapFree(GetProcessHeap(), 0, whdd->lpvbuf);*/
149 
150     if (whdd->hMemDC)
151     {
152         SelectObject(whdd->hMemDC, whdd->hOldDib);
153         DeleteDC(whdd->hMemDC);
154         whdd->hMemDC = 0;
155     }
156 
157     if (whdd->hDib) DeleteObject(whdd->hDib);
158     whdd->hDib = 0;
159 
160     if (whdd->hic)
161     {
162         ICDecompressEnd(whdd->hic);
163         ICClose(whdd->hic);
164         whdd->hic = 0;
165     }
166 
167     whdd->lpvbits = NULL;
168 
169     return ret;
170 }
171 
172 /***********************************************************************
173  *              DrawDibBegin            [MSVFW32.@]
174  */
175 BOOL VFWAPI DrawDibBegin(HDRAWDIB hdd,
176                          HDC      hdc,
177                          INT      dxDst,
178                          INT      dyDst,
179                          LPBITMAPINFOHEADER lpbi,
180                          INT      dxSrc,
181                          INT      dySrc,
182                          UINT     wFlags)
183 {
184     BOOL ret = TRUE;
185     WINE_HDD *whdd;
186 
187     TRACE("(%p,%p,%d,%d,%p,%d,%d,0x%08x)\n",
188           hdd, hdc, dxDst, dyDst, lpbi, dxSrc, dySrc, wFlags);
189 
190     TRACE("lpbi: %d,%d/%d,%d,%d,%d,%d,%d,%d,%d,%d\n",
191           lpbi->biSize, lpbi->biWidth, lpbi->biHeight, lpbi->biPlanes,
192           lpbi->biBitCount, lpbi->biCompression, lpbi->biSizeImage,
193           lpbi->biXPelsPerMeter, lpbi->biYPelsPerMeter, lpbi->biClrUsed,
194           lpbi->biClrImportant);
195 
196     if (wFlags & ~(DDF_BUFFER))
197         FIXME("wFlags == 0x%08x not handled\n", wFlags & ~(DDF_BUFFER));
198 
199     whdd = MSVIDEO_GetHddPtr(hdd);
200     if (!whdd) return FALSE;
201 
202     if (whdd->begun) DrawDibEnd(hdd);
203 
204     if (lpbi->biCompression)
205     {
206         DWORD size = 0;
207 
208         whdd->hic = ICOpen(ICTYPE_VIDEO, lpbi->biCompression, ICMODE_DECOMPRESS);
209         if (!whdd->hic)
210         {
211             WARN("Could not open IC. biCompression == 0x%08x\n", lpbi->biCompression);
212             ret = FALSE;
213         }
214 
215         if (ret)
216         {
217             size = ICDecompressGetFormat(whdd->hic, lpbi, NULL);
218             if (size == ICERR_UNSUPPORTED)
219             {
220                 WARN("Codec doesn't support GetFormat, giving up.\n");
221                 ret = FALSE;
222             }
223         }
224 
225         if (ret)
226         {
227             whdd->lpbiOut = HeapAlloc(GetProcessHeap(), 0, size);
228 
229             if (ICDecompressGetFormat(whdd->hic, lpbi, whdd->lpbiOut) != ICERR_OK)
230                 ret = FALSE;
231         }
232 
233         if (ret)
234         {
235             /* FIXME: Use Ex functions if available? */
236             if (ICDecompressBegin(whdd->hic, lpbi, whdd->lpbiOut) != ICERR_OK)
237                 ret = FALSE;
238 
239             TRACE("biSizeImage == %d\n", whdd->lpbiOut->biSizeImage);
240             TRACE("biCompression == %d\n", whdd->lpbiOut->biCompression);
241             TRACE("biBitCount == %d\n", whdd->lpbiOut->biBitCount);
242         }
243     }
244     else
245     {
246         DWORD dwSize;
247         /* No compression */
248         TRACE("Not compressed!\n");
249         if (lpbi->biHeight <= 0)
250         {
251             /* we don't draw inverted DIBs */
252             TRACE("detected inverted DIB\n");
253             ret = FALSE;
254         }
255         else
256         {
257             dwSize = lpbi->biSize + num_colours(lpbi)*sizeof(RGBQUAD);
258             whdd->lpbiOut = HeapAlloc(GetProcessHeap(), 0, dwSize);
259             memcpy(whdd->lpbiOut, lpbi, dwSize);
260         }
261     }
262 
263     if (ret)
264     {
265         /*whdd->lpvbuf = HeapAlloc(GetProcessHeap(), 0, whdd->lpbiOut->biSizeImage);*/
266 
267         whdd->hMemDC = CreateCompatibleDC(hdc);
268         TRACE("Creating: %d, %p\n", whdd->lpbiOut->biSize, whdd->lpvbits);
269         whdd->hDib = CreateDIBSection(whdd->hMemDC, (BITMAPINFO *)whdd->lpbiOut, DIB_RGB_COLORS, &(whdd->lpvbits), 0, 0);
270         if (whdd->hDib)
271         {
272             TRACE("Created: %p,%p\n", whdd->hDib, whdd->lpvbits);
273         }
274         else
275         {
276             ret = FALSE;
277             TRACE("Error: %d\n", GetLastError());
278         }
279         whdd->hOldDib = SelectObject(whdd->hMemDC, whdd->hDib);
280     }
281 
282     if (ret)
283     {
284         whdd->hdc = hdc;
285         whdd->dxDst = dxDst;
286         whdd->dyDst = dyDst;
287         whdd->lpbi = HeapAlloc(GetProcessHeap(), 0, lpbi->biSize);
288         memcpy(whdd->lpbi, lpbi, lpbi->biSize);
289         whdd->dxSrc = dxSrc;
290         whdd->dySrc = dySrc;
291         whdd->begun = TRUE;
292         whdd->hpal = 0;
293     }
294     else
295     {
296         if (whdd->hic)
297             ICClose(whdd->hic);
298         HeapFree(GetProcessHeap(), 0, whdd->lpbiOut);
299         whdd->lpbiOut = NULL;
300     }
301 
302     return ret;
303 }
304 
305 /**********************************************************************
306  *		DrawDibDraw		[MSVFW32.@]
307  */
308 BOOL VFWAPI DrawDibDraw(HDRAWDIB hdd, HDC hdc,
309                         INT xDst, INT yDst, INT dxDst, INT dyDst,
310                         LPBITMAPINFOHEADER lpbi,
311                         LPVOID lpBits,
312                         INT xSrc, INT ySrc, INT dxSrc, INT dySrc,
313                         UINT wFlags)
314 {
315     WINE_HDD *whdd;
316     BOOL ret;
317     int reopen = 0;
318 
319     TRACE("(%p,%p,%d,%d,%d,%d,%p,%p,%d,%d,%d,%d,0x%08x)\n",
320           hdd, hdc, xDst, yDst, dxDst, dyDst, lpbi, lpBits, xSrc, ySrc, dxSrc, dySrc, wFlags);
321 
322     whdd = MSVIDEO_GetHddPtr(hdd);
323     if (!whdd) return FALSE;
324 
325     TRACE("whdd=%p\n", whdd);
326 
327     if (wFlags & ~(DDF_SAME_HDC | DDF_SAME_DRAW | DDF_NOTKEYFRAME | DDF_UPDATE | DDF_DONTDRAW | DDF_BACKGROUNDPAL))
328         FIXME("wFlags == 0x%08x not handled\n", wFlags);
329 
330     if (!lpBits)
331     {
332         /* Undocumented? */
333         lpBits = (LPSTR)lpbi + (WORD)(lpbi->biSize) + (WORD)(num_colours(lpbi)*sizeof(RGBQUAD));
334     }
335 
336 
337 #define CHANGED(x) (whdd->x != x)
338 
339     /* Check if anything changed from the parameters passed and our struct.
340      * If anything changed we need to run DrawDibBegin again to ensure we
341      * can support the changes.
342      */
343     if (!whdd->begun)
344         reopen = 1;
345     else if (!(wFlags & DDF_SAME_HDC) && CHANGED(hdc))
346         reopen = 2;
347     else if (!(wFlags & DDF_SAME_DRAW))
348     {
349         if (CHANGED(lpbi) && memcmp(lpbi, whdd->lpbi, sizeof(*lpbi))) reopen = 3;
350         else if (CHANGED(dxSrc)) reopen = 4;
351         else if (CHANGED(dySrc)) reopen = 5;
352         else if (CHANGED(dxDst)) reopen = 6;
353         else if (CHANGED(dyDst)) reopen = 7;
354     }
355     if (reopen)
356     {
357         TRACE("Something changed (reason %d)!\n", reopen);
358         ret = DrawDibBegin(hdd, hdc, dxDst, dyDst, lpbi, dxSrc, dySrc, 0);
359         if (!ret)
360             return ret;
361     }
362 
363 #undef CHANGED
364 
365     /* If source dimensions are not specified derive them from bitmap header */
366     if (dxSrc == -1 && dySrc == -1)
367     {
368         dxSrc = lpbi->biWidth;
369         dySrc = lpbi->biHeight;
370     }
371     /* If destination dimensions are not specified derive them from source */
372     if (dxDst == -1 && dyDst == -1)
373     {
374         dxDst = dxSrc;
375         dyDst = dySrc;
376     }
377 
378     if (!(wFlags & DDF_UPDATE))
379     {
380         if (lpbi->biCompression)
381         {
382             DWORD flags = 0;
383 
384             TRACE("Compression == 0x%08x\n", lpbi->biCompression);
385 
386             if (wFlags & DDF_NOTKEYFRAME)
387                 flags |= ICDECOMPRESS_NOTKEYFRAME;
388 
389             ICDecompress(whdd->hic, flags, lpbi, lpBits, whdd->lpbiOut, whdd->lpvbits);
390         }
391         else
392         {
393             /* BI_RGB: lpbi->biSizeImage isn't reliable */
394             DWORD biSizeImage = ((lpbi->biWidth * lpbi->biBitCount + 31) / 32) * 4 * lpbi->biHeight;
395             memcpy(whdd->lpvbits, lpBits, biSizeImage);
396         }
397     }
398     if (!(wFlags & DDF_DONTDRAW) && whdd->hpal)
399     {
400         if ((wFlags & DDF_BACKGROUNDPAL) && ! (wFlags & DDF_SAME_HDC))
401          SelectPalette(hdc, whdd->hpal, TRUE);
402         else
403          SelectPalette(hdc, whdd->hpal, FALSE);
404     }
405 
406     ret = StretchBlt(whdd->hdc, xDst, yDst, dxDst, dyDst, whdd->hMemDC, xSrc, ySrc, dxSrc, dySrc, SRCCOPY);
407     TRACE("Painting %dx%d at %d,%d from %dx%d at %d,%d -> %d\n",
408           dxDst, dyDst, xDst, yDst, dxSrc, dySrc, xSrc, ySrc, ret);
409 
410     return ret;
411 }
412 
413 /*************************************************************************
414  *		DrawDibStart		[MSVFW32.@]
415  */
416 BOOL VFWAPI DrawDibStart(HDRAWDIB hdd, DWORD rate) {
417 	FIXME("(%p, %d), stub\n", hdd, rate);
418 	return TRUE;
419 }
420 
421 /*************************************************************************
422  *		DrawDibStop		[MSVFW32.@]
423  */
424 BOOL VFWAPI DrawDibStop(HDRAWDIB hdd) {
425 	FIXME("(%p), stub\n", hdd);
426 	return TRUE;
427 }
428 
429 /***********************************************************************
430  *              DrawDibChangePalette       [MSVFW32.@]
431  */
432 BOOL VFWAPI DrawDibChangePalette(HDRAWDIB hdd, int iStart, int iLen, LPPALETTEENTRY lppe)
433 {
434     FIXME("(%p, 0x%08x, 0x%08x, %p), stub\n", hdd, iStart, iLen, lppe);
435     return TRUE;
436 }
437 
438 /***********************************************************************
439  *              DrawDibSetPalette       [MSVFW32.@]
440  */
441 BOOL VFWAPI DrawDibSetPalette(HDRAWDIB hdd, HPALETTE hpal)
442 {
443     WINE_HDD *whdd;
444 
445     TRACE("(%p, %p)\n", hdd, hpal);
446 
447     whdd = MSVIDEO_GetHddPtr(hdd);
448     if (!whdd) return FALSE;
449 
450     whdd->hpal = hpal;
451 
452     if (whdd->begun)
453     {
454         SelectPalette(whdd->hdc, hpal, 0);
455         RealizePalette(whdd->hdc);
456     }
457 
458     return TRUE;
459 }
460 
461 /***********************************************************************
462  *              DrawDibGetBuffer       [MSVFW32.@]
463  */
464 LPVOID VFWAPI DrawDibGetBuffer(HDRAWDIB hdd, LPBITMAPINFOHEADER lpbi, DWORD dwSize, DWORD dwFlags)
465 {
466     FIXME("(%p, %p, 0x%08x, 0x%08x), stub\n", hdd, lpbi, dwSize, dwFlags);
467     return NULL;
468 }
469 
470 /***********************************************************************
471  *              DrawDibGetPalette       [MSVFW32.@]
472  */
473 HPALETTE VFWAPI DrawDibGetPalette(HDRAWDIB hdd)
474 {
475     WINE_HDD *whdd;
476 
477     TRACE("(%p)\n", hdd);
478 
479     whdd = MSVIDEO_GetHddPtr(hdd);
480     if (!whdd) return FALSE;
481 
482     return whdd->hpal;
483 }
484 
485 /***********************************************************************
486  *              DrawDibRealize          [MSVFW32.@]
487  */
488 UINT VFWAPI DrawDibRealize(HDRAWDIB hdd, HDC hdc, BOOL fBackground)
489 {
490     WINE_HDD *whdd;
491     UINT ret = 0;
492 
493     FIXME("(%p, %p, %d), stub\n", hdd, hdc, fBackground);
494 
495     whdd = MSVIDEO_GetHddPtr(hdd);
496     if (!whdd) return FALSE;
497 
498     if (!whdd->begun)
499     {
500         ret = 0;
501         goto out;
502     }
503 
504     if (!whdd->hpal)
505         whdd->hpal = CreateHalftonePalette(hdc);
506 
507     SelectPalette(hdc, whdd->hpal, fBackground);
508     ret = RealizePalette(hdc);
509 
510  out:
511     TRACE("=> %u\n", ret);
512     return ret;
513 }
514 
515 /***********************************************************************
516  *              DrawDibTime          [MSVFW32.@]
517  */
518 BOOL VFWAPI DrawDibTime(HDRAWDIB hdd, LPDRAWDIBTIME lpddtime)
519 {
520     FIXME("(%p, %p) stub\n", hdd, lpddtime);
521     return FALSE;
522 }
523 
524 /***********************************************************************
525  *              DrawDibProfileDisplay          [MSVFW32.@]
526  */
527 DWORD VFWAPI DrawDibProfileDisplay(LPBITMAPINFOHEADER lpbi)
528 {
529     FIXME("(%p) stub\n", lpbi);
530 
531     return PD_CAN_DRAW_DIB;
532 }
533