If the driver doesn't support StretchBlt try to use StretchDIBits
[wine] / dlls / gdi / bitblt.c
1 /*
2  * GDI bit-blit operations
3  *
4  * Copyright 1993, 1994  Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "gdi.h"
22 #include "gdi_private.h"
23 #include "wine/debug.h"
24
25 WINE_DEFAULT_DEBUG_CHANNEL(bitblt);
26
27
28 /***********************************************************************
29  *           PatBlt    (GDI32.@)
30  */
31 BOOL WINAPI PatBlt( HDC hdc, INT left, INT top,
32                         INT width, INT height, DWORD rop)
33 {
34     DC * dc = DC_GetDCUpdate( hdc );
35     BOOL bRet = FALSE;
36
37     if (!dc) return FALSE;
38
39     if (dc->funcs->pPatBlt)
40     {
41         TRACE("%p %d,%d %dx%d %06lx\n", hdc, left, top, width, height, rop );
42         bRet = dc->funcs->pPatBlt( dc->physDev, left, top, width, height, rop );
43     }
44     GDI_ReleaseObj( hdc );
45     return bRet;
46 }
47
48
49 /***********************************************************************
50  *           BitBlt    (GDI32.@)
51  */
52 BOOL WINAPI BitBlt( HDC hdcDst, INT xDst, INT yDst, INT width,
53                     INT height, HDC hdcSrc, INT xSrc, INT ySrc, DWORD rop )
54 {
55     BOOL ret = FALSE;
56     DC *dcDst, *dcSrc;
57
58     if ((dcSrc = DC_GetDCUpdate( hdcSrc ))) GDI_ReleaseObj( hdcSrc );
59     /* FIXME: there is a race condition here */
60     if ((dcDst = DC_GetDCUpdate( hdcDst )))
61     {
62         dcSrc = DC_GetDCPtr( hdcSrc );
63         TRACE("hdcSrc=%p %d,%d -> hdcDest=%p %d,%d %dx%d rop=%06lx\n",
64               hdcSrc, xSrc, ySrc, hdcDst, xDst, yDst, width, height, rop);
65         if (dcDst->funcs->pBitBlt)
66             ret = dcDst->funcs->pBitBlt( dcDst->physDev, xDst, yDst, width, height,
67                                          dcSrc ? dcSrc->physDev : NULL, xSrc, ySrc, rop );
68         if (dcSrc) GDI_ReleaseObj( hdcSrc );
69         GDI_ReleaseObj( hdcDst );
70     }
71     return ret;
72 }
73
74
75 /***********************************************************************
76  *           StretchBlt    (GDI32.@)
77  */
78 BOOL WINAPI StretchBlt( HDC hdcDst, INT xDst, INT yDst,
79                             INT widthDst, INT heightDst,
80                             HDC hdcSrc, INT xSrc, INT ySrc,
81                             INT widthSrc, INT heightSrc,
82                         DWORD rop )
83 {
84     BOOL ret = FALSE;
85     DC *dcDst, *dcSrc;
86
87     if ((dcDst = DC_GetDCUpdate( hdcDst )) && dcDst->funcs->pStretchBlt)
88     {
89         GDI_ReleaseObj( hdcDst );
90         /* FIXME: there is a race condition here */
91         if ((dcSrc = DC_GetDCUpdate( hdcSrc )))
92         {
93             dcDst = DC_GetDCPtr( hdcDst );
94
95             TRACE("%p %d,%d %dx%d -> %p %d,%d %dx%d rop=%06lx\n",
96                   hdcSrc, xSrc, ySrc, widthSrc, heightSrc,
97                   hdcDst, xDst, yDst, widthDst, heightDst, rop );
98
99             ret = dcDst->funcs->pStretchBlt( dcDst->physDev, xDst, yDst, widthDst, heightDst,
100                                              dcSrc->physDev, xSrc, ySrc, widthSrc, heightSrc,
101                                              rop );
102             GDI_ReleaseObj( hdcDst );
103             GDI_ReleaseObj( hdcSrc );
104         }
105     }
106     else if(dcDst && dcDst->funcs->pStretchDIBits)
107     {
108         BITMAP bm;
109         BITMAPINFOHEADER info_hdr;
110         HBITMAP hbm;
111         LPVOID bits;
112         INT lines;
113
114         GDI_ReleaseObj( hdcDst );
115
116         if(GetObjectType( hdcSrc ) != OBJ_MEMDC) return FALSE;
117
118         GetObjectW(GetCurrentObject(hdcSrc, OBJ_BITMAP), sizeof(bm), &bm);
119  
120         info_hdr.biSize = sizeof(info_hdr);
121         info_hdr.biWidth = bm.bmWidth;
122         info_hdr.biHeight = bm.bmHeight;
123         info_hdr.biPlanes = 1;
124         info_hdr.biBitCount = 32;
125         info_hdr.biCompression = BI_RGB;
126         info_hdr.biSizeImage = 0;
127         info_hdr.biXPelsPerMeter = 0;
128         info_hdr.biYPelsPerMeter = 0;
129         info_hdr.biClrUsed = 0;
130         info_hdr.biClrImportant = 0;
131
132         if(!(bits = HeapAlloc(GetProcessHeap(), 0, bm.bmHeight * bm.bmWidth * 4)))
133             return FALSE;
134
135         /* Select out the src bitmap before calling GetDIBits */
136         hbm = SelectObject(hdcSrc, GetStockObject(DEFAULT_BITMAP));
137         GetDIBits(hdcSrc, hbm, 0, bm.bmHeight, bits, (BITMAPINFO*)&info_hdr, DIB_RGB_COLORS);
138         SelectObject(hdcSrc, hbm);
139
140         lines = StretchDIBits(hdcDst, xDst, yDst, widthDst, heightDst, xSrc, ySrc, widthSrc, heightSrc,
141                               bits, (BITMAPINFO*)&info_hdr, DIB_RGB_COLORS, rop);
142
143         HeapFree(GetProcessHeap(), 0, bits);
144         return (lines == bm.bmHeight);
145     }
146     else if(dcDst)
147         GDI_ReleaseObj( hdcDst );
148
149     return ret;
150 }
151
152 #define FRGND_ROP3(ROP4)        ((ROP4) & 0x00FFFFFF)
153 #define BKGND_ROP3(ROP4)        (ROP3Table[((ROP4)>>24) & 0xFF])
154
155 /***********************************************************************
156  *           MaskBlt [GDI32.@]
157  */
158 BOOL WINAPI MaskBlt(HDC hdcDest, INT nXDest, INT nYDest,
159                         INT nWidth, INT nHeight, HDC hdcSrc,
160                         INT nXSrc, INT nYSrc, HBITMAP hbmMask,
161                         INT xMask, INT yMask, DWORD dwRop)
162 {
163     HBITMAP hBitmap1, hOldBitmap1, hBitmap2, hOldBitmap2;
164     HDC hDC1, hDC2;
165     HBRUSH hbrMask, hbrDst, hbrTmp;
166
167     static const DWORD ROP3Table[256] = 
168     {
169         0x00000042, 0x00010289,
170         0x00020C89, 0x000300AA,
171         0x00040C88, 0x000500A9,
172         0x00060865, 0x000702C5,
173         0x00080F08, 0x00090245,
174         0x000A0329, 0x000B0B2A,
175         0x000C0324, 0x000D0B25,
176         0x000E08A5, 0x000F0001,
177         0x00100C85, 0x001100A6,
178         0x00120868, 0x001302C8,
179         0x00140869, 0x001502C9,
180         0x00165CCA, 0x00171D54,
181         0x00180D59, 0x00191CC8,
182         0x001A06C5, 0x001B0768,
183         0x001C06CA, 0x001D0766,
184         0x001E01A5, 0x001F0385,
185         0x00200F09, 0x00210248,
186         0x00220326, 0x00230B24,
187         0x00240D55, 0x00251CC5,
188         0x002606C8, 0x00271868,
189         0x00280369, 0x002916CA,
190         0x002A0CC9, 0x002B1D58,
191         0x002C0784, 0x002D060A,
192         0x002E064A, 0x002F0E2A,
193         0x0030032A, 0x00310B28,
194         0x00320688, 0x00330008,
195         0x003406C4, 0x00351864,
196         0x003601A8, 0x00370388,
197         0x0038078A, 0x00390604,
198         0x003A0644, 0x003B0E24,
199         0x003C004A, 0x003D18A4,
200         0x003E1B24, 0x003F00EA,
201         0x00400F0A, 0x00410249,
202         0x00420D5D, 0x00431CC4,
203         0x00440328, 0x00450B29,
204         0x004606C6, 0x0047076A,
205         0x00480368, 0x004916C5,
206         0x004A0789, 0x004B0605,
207         0x004C0CC8, 0x004D1954,
208         0x004E0645, 0x004F0E25,
209         0x00500325, 0x00510B26,
210         0x005206C9, 0x00530764,
211         0x005408A9, 0x00550009,
212         0x005601A9, 0x00570389,
213         0x00580785, 0x00590609,
214         0x005A0049, 0x005B18A9,
215         0x005C0649, 0x005D0E29,
216         0x005E1B29, 0x005F00E9,
217         0x00600365, 0x006116C6,
218         0x00620786, 0x00630608,
219         0x00640788, 0x00650606,
220         0x00660046, 0x006718A8,
221         0x006858A6, 0x00690145,
222         0x006A01E9, 0x006B178A,
223         0x006C01E8, 0x006D1785,
224         0x006E1E28, 0x006F0C65,
225         0x00700CC5, 0x00711D5C,
226         0x00720648, 0x00730E28,
227         0x00740646, 0x00750E26,
228         0x00761B28, 0x007700E6,
229         0x007801E5, 0x00791786,
230         0x007A1E29, 0x007B0C68,
231         0x007C1E24, 0x007D0C69,
232         0x007E0955, 0x007F03C9,
233         0x008003E9, 0x00810975,
234         0x00820C49, 0x00831E04,
235         0x00840C48, 0x00851E05,
236         0x008617A6, 0x008701C5,
237         0x008800C6, 0x00891B08,
238         0x008A0E06, 0x008B0666,
239         0x008C0E08, 0x008D0668,
240         0x008E1D7C, 0x008F0CE5,
241         0x00900C45, 0x00911E08,
242         0x009217A9, 0x009301C4,
243         0x009417AA, 0x009501C9,
244         0x00960169, 0x0097588A,
245         0x00981888, 0x00990066,
246         0x009A0709, 0x009B07A8,
247         0x009C0704, 0x009D07A6,
248         0x009E16E6, 0x009F0345,
249         0x00A000C9, 0x00A11B05,
250         0x00A20E09, 0x00A30669,
251         0x00A41885, 0x00A50065,
252         0x00A60706, 0x00A707A5,
253         0x00A803A9, 0x00A90189,
254         0x00AA0029, 0x00AB0889,
255         0x00AC0744, 0x00AD06E9,
256         0x00AE0B06, 0x00AF0229,
257         0x00B00E05, 0x00B10665,
258         0x00B21974, 0x00B30CE8,
259         0x00B4070A, 0x00B507A9,
260         0x00B616E9, 0x00B70348,
261         0x00B8074A, 0x00B906E6,
262         0x00BA0B09, 0x00BB0226,
263         0x00BC1CE4, 0x00BD0D7D,
264         0x00BE0269, 0x00BF08C9,
265         0x00C000CA, 0x00C11B04,
266         0x00C21884, 0x00C3006A,
267         0x00C40E04, 0x00C50664,
268         0x00C60708, 0x00C707AA,
269         0x00C803A8, 0x00C90184,
270         0x00CA0749, 0x00CB06E4,
271         0x00CC0020, 0x00CD0888,
272         0x00CE0B08, 0x00CF0224,
273         0x00D00E0A, 0x00D1066A,
274         0x00D20705, 0x00D307A4,
275         0x00D41D78, 0x00D50CE9,
276         0x00D616EA, 0x00D70349,
277         0x00D80745, 0x00D906E8,
278         0x00DA1CE9, 0x00DB0D75,
279         0x00DC0B04, 0x00DD0228,
280         0x00DE0268, 0x00DF08C8,
281         0x00E003A5, 0x00E10185,
282         0x00E20746, 0x00E306EA,
283         0x00E40748, 0x00E506E5,
284         0x00E61CE8, 0x00E70D79,
285         0x00E81D74, 0x00E95CE6,
286         0x00EA02E9, 0x00EB0849,
287         0x00EC02E8, 0x00ED0848,
288         0x00EE0086, 0x00EF0A08,
289         0x00F00021, 0x00F10885,
290         0x00F20B05, 0x00F3022A,
291         0x00F40B0A, 0x00F50225,
292         0x00F60265, 0x00F708C5,
293         0x00F802E5, 0x00F90845,
294         0x00FA0089, 0x00FB0A09,
295         0x00FC008A, 0x00FD0A0A,
296         0x00FE02A9, 0x00FF0062,
297     };
298
299     if (!hbmMask)
300         return BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
301
302     hbrMask = CreatePatternBrush(hbmMask);
303     hbrDst = SelectObject(hdcDest, GetStockObject(NULL_BRUSH));
304
305     /* make bitmap */
306     hDC1 = CreateCompatibleDC(hdcDest);
307     hBitmap1 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
308     hOldBitmap1 = SelectObject(hDC1, hBitmap1);
309
310     /* draw using bkgnd rop */
311     BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
312     hbrTmp = SelectObject(hDC1, hbrDst);
313     BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, BKGND_ROP3(dwRop));
314     SelectObject(hDC1, hbrTmp);
315
316     /* make bitmap */
317     hDC2 = CreateCompatibleDC(hdcDest);
318     hBitmap2 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
319     hOldBitmap2 = SelectObject(hDC2, hBitmap2);
320
321     /* draw using foregnd rop */
322     BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
323     hbrTmp = SelectObject(hDC2, hbrDst);
324     BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
325
326     /* combine both using the mask as a pattern brush */
327     SelectObject(hDC2, hbrMask);
328     BitBlt(hDC2, 0, 0, nWidth, nHeight, hDC1, 0, 0, 0xac0744 ); /* (D & P) | (S & ~P) */ 
329     SelectObject(hDC2, hbrTmp);
330
331     /* blit to dst */
332     BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hDC2, 0, 0, SRCCOPY);
333
334     /* restore all objects */
335     SelectObject(hdcDest, hbrDst);
336     SelectObject(hDC1, hOldBitmap1);
337     SelectObject(hDC2, hOldBitmap2);
338
339     /* delete all temp objects */
340     DeleteObject(hBitmap1);
341     DeleteObject(hBitmap2);
342     DeleteObject(hbrMask);
343
344     DeleteDC(hDC1);
345     DeleteDC(hDC2);
346
347     return TRUE;
348 }
349
350 /******************************************************************************
351  *           GdiTransparentBlt [GDI32.@]
352  */
353 BOOL WINAPI GdiTransparentBlt( HDC hdcDest, int xDest, int yDest, int widthDest, int heightDest,
354                             HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
355                             UINT crTransparent )
356 {
357     BOOL ret = FALSE;
358     HDC hdcWork;
359     HBITMAP bmpWork;
360     HGDIOBJ oldWork;
361     HDC hdcMask = NULL;
362     HBITMAP bmpMask = NULL;
363     HBITMAP oldMask = NULL;
364     COLORREF oldBackground;
365     COLORREF oldForeground;
366     int oldStretchMode;
367
368     if(widthDest < 0 || heightDest < 0 || widthSrc < 0 || heightSrc < 0) {
369         TRACE("Cannot mirror\n");
370         return FALSE;
371     }
372
373     oldBackground = SetBkColor(hdcDest, RGB(255,255,255));
374     oldForeground = SetTextColor(hdcDest, RGB(0,0,0));
375
376     /* Stretch bitmap */
377     oldStretchMode = GetStretchBltMode(hdcSrc);
378     if(oldStretchMode == BLACKONWHITE || oldStretchMode == WHITEONBLACK)
379         SetStretchBltMode(hdcSrc, COLORONCOLOR);
380     hdcWork = CreateCompatibleDC(hdcDest);
381     bmpWork = CreateCompatibleBitmap(hdcDest, widthDest, heightDest);
382     oldWork = SelectObject(hdcWork, bmpWork);
383     if(!StretchBlt(hdcWork, 0, 0, widthDest, heightDest, hdcSrc, xSrc, ySrc, widthSrc, heightSrc, SRCCOPY)) {
384         TRACE("Failed to stretch\n");
385         goto error;
386     }
387     SetBkColor(hdcWork, crTransparent);
388
389     /* Create mask */
390     hdcMask = CreateCompatibleDC(hdcDest);
391     bmpMask = CreateCompatibleBitmap(hdcMask, widthDest, heightDest);
392     oldMask = SelectObject(hdcMask, bmpMask);
393     if(!BitBlt(hdcMask, 0, 0, widthDest, heightDest, hdcWork, 0, 0, SRCCOPY)) {
394         TRACE("Failed to create mask\n");
395         goto error;
396     }
397
398     /* Replace transparent color with black */
399     SetBkColor(hdcWork, RGB(0,0,0));
400     SetTextColor(hdcWork, RGB(255,255,255));
401     if(!BitBlt(hdcWork, 0, 0, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
402         TRACE("Failed to mask out background\n");
403         goto error;
404     }
405
406     /* Replace non-transparent area on destination with black */
407     if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
408         TRACE("Failed to clear destination area\n");
409         goto error;
410     }
411
412     /* Draw the image */
413     if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcWork, 0, 0, SRCPAINT)) {
414         TRACE("Failed to paint image\n");
415         goto error;
416     }
417
418     ret = TRUE;
419 error:
420     SetStretchBltMode(hdcSrc, oldStretchMode);
421     SetBkColor(hdcDest, oldBackground);
422     SetTextColor(hdcDest, oldForeground);
423     if(hdcWork) {
424         SelectObject(hdcWork, oldWork);
425         DeleteDC(hdcWork);
426     }
427     if(bmpWork) DeleteObject(bmpWork);
428     if(hdcMask) {
429         SelectObject(hdcMask, oldMask);
430         DeleteDC(hdcMask);
431     }
432     if(bmpMask) DeleteObject(bmpMask);
433     return ret;
434 }
435
436 /******************************************************************************
437  *           GdiAlphaBlend [GDI32.@]
438  */
439 BOOL WINAPI GdiAlphaBlend(HDC hdcDst, int xDst, int yDst, int widthDst, int heightDst,
440                           HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
441                           BLENDFUNCTION blendFunction)
442 {
443     BOOL ret = FALSE;
444     DC *dcDst, *dcSrc;
445
446     if ((dcSrc = DC_GetDCUpdate( hdcSrc ))) GDI_ReleaseObj( hdcSrc );
447     /* FIXME: there is a race condition here */
448     if ((dcDst = DC_GetDCUpdate( hdcDst )))
449     {
450         dcSrc = DC_GetDCPtr( hdcSrc );
451         TRACE("%p %d,%d %dx%d -> %p %d,%d %dx%d op=%02x flags=%02x srcconstalpha=%02x alphafmt=%02x\n",
452               hdcSrc, xSrc, ySrc, widthSrc, heightSrc,
453               hdcDst, xDst, yDst, widthDst, heightDst,
454               blendFunction.BlendOp, blendFunction.BlendFlags,
455               blendFunction.SourceConstantAlpha, blendFunction.AlphaFormat);
456         if (dcDst->funcs->pAlphaBlend)
457             ret = dcDst->funcs->pAlphaBlend( dcDst->physDev, xDst, yDst, widthDst, heightDst,
458                                              dcSrc ? dcSrc->physDev : NULL,
459                                              xSrc, ySrc, widthSrc, heightSrc, blendFunction );
460         if (dcSrc) GDI_ReleaseObj( hdcSrc );
461         GDI_ReleaseObj( hdcDst );
462     }
463     return ret;
464 }
465
466 /*********************************************************************
467  *      PlgBlt [GDI32.@]
468  *
469  */
470 BOOL WINAPI PlgBlt( HDC hdcDest, const POINT *lpPoint,
471                         HDC hdcSrc, INT nXDest, INT nYDest, INT nWidth,
472                         INT nHeight, HBITMAP hbmMask, INT xMask, INT yMask)
473 {
474     FIXME("PlgBlt, stub\n");
475         return 1;
476 }