Fix maskblt to work with any set of rops and to also take into account
[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 ((dcSrc = DC_GetDCUpdate( hdcSrc ))) GDI_ReleaseObj( hdcSrc );
88     /* FIXME: there is a race condition here */
89     if ((dcDst = DC_GetDCUpdate( hdcDst )))
90     {
91         dcSrc = DC_GetDCPtr( hdcSrc );
92
93         TRACE("%p %d,%d %dx%d -> %p %d,%d %dx%d rop=%06lx\n",
94               hdcSrc, xSrc, ySrc, widthSrc, heightSrc,
95               hdcDst, xDst, yDst, widthDst, heightDst, rop );
96
97         if (dcSrc) {
98             if (dcDst->funcs->pStretchBlt)
99                 ret = dcDst->funcs->pStretchBlt( dcDst->physDev, xDst, yDst, widthDst, heightDst,
100                                                  dcSrc->physDev, xSrc, ySrc, widthSrc, heightSrc,
101                                                  rop );
102             GDI_ReleaseObj( hdcSrc );
103         }
104         GDI_ReleaseObj( hdcDst );
105     }
106     return ret;
107 }
108
109 #define FRGND_ROP3(ROP4)        ((ROP4) & 0x00FFFFFF)
110 #define BKGND_ROP3(ROP4)        (ROP3Table[((ROP4)>>24) & 0xFF])
111
112 /***********************************************************************
113  *           MaskBlt [GDI32.@]
114  */
115 BOOL WINAPI MaskBlt(HDC hdcDest, INT nXDest, INT nYDest,
116                         INT nWidth, INT nHeight, HDC hdcSrc,
117                         INT nXSrc, INT nYSrc, HBITMAP hbmMask,
118                         INT xMask, INT yMask, DWORD dwRop)
119 {
120     HBITMAP hBitmap1, hOldBitmap1, hBitmap2, hOldBitmap2;
121     HDC hDC1, hDC2;
122     HBRUSH hbrMask, hbrDst, hbrTmp;
123
124     static const DWORD ROP3Table[256] = 
125     {
126         0x00000042, 0x00010289,
127         0x00020C89, 0x000300AA,
128         0x00040C88, 0x000500A9,
129         0x00060865, 0x000702C5,
130         0x00080F08, 0x00090245,
131         0x000A0329, 0x000B0B2A,
132         0x000C0324, 0x000D0B25,
133         0x000E08A5, 0x000F0001,
134         0x00100C85, 0x001100A6,
135         0x00120868, 0x001302C8,
136         0x00140869, 0x001502C9,
137         0x00165CCA, 0x00171D54,
138         0x00180D59, 0x00191CC8,
139         0x001A06C5, 0x001B0768,
140         0x001C06CA, 0x001D0766,
141         0x001E01A5, 0x001F0385,
142         0x00200F09, 0x00210248,
143         0x00220326, 0x00230B24,
144         0x00240D55, 0x00251CC5,
145         0x002606C8, 0x00271868,
146         0x00280369, 0x002916CA,
147         0x002A0CC9, 0x002B1D58,
148         0x002C0784, 0x002D060A,
149         0x002E064A, 0x002F0E2A,
150         0x0030032A, 0x00310B28,
151         0x00320688, 0x00330008,
152         0x003406C4, 0x00351864,
153         0x003601A8, 0x00370388,
154         0x0038078A, 0x00390604,
155         0x003A0644, 0x003B0E24,
156         0x003C004A, 0x003D18A4,
157         0x003E1B24, 0x003F00EA,
158         0x00400F0A, 0x00410249,
159         0x00420D5D, 0x00431CC4,
160         0x00440328, 0x00450B29,
161         0x004606C6, 0x0047076A,
162         0x00480368, 0x004916C5,
163         0x004A0789, 0x004B0605,
164         0x004C0CC8, 0x004D1954,
165         0x004E0645, 0x004F0E25,
166         0x00500325, 0x00510B26,
167         0x005206C9, 0x00530764,
168         0x005408A9, 0x00550009,
169         0x005601A9, 0x00570389,
170         0x00580785, 0x00590609,
171         0x005A0049, 0x005B18A9,
172         0x005C0649, 0x005D0E29,
173         0x005E1B29, 0x005F00E9,
174         0x00600365, 0x006116C6,
175         0x00620786, 0x00630608,
176         0x00640788, 0x00650606,
177         0x00660046, 0x006718A8,
178         0x006858A6, 0x00690145,
179         0x006A01E9, 0x006B178A,
180         0x006C01E8, 0x006D1785,
181         0x006E1E28, 0x006F0C65,
182         0x00700CC5, 0x00711D5C,
183         0x00720648, 0x00730E28,
184         0x00740646, 0x00750E26,
185         0x00761B28, 0x007700E6,
186         0x007801E5, 0x00791786,
187         0x007A1E29, 0x007B0C68,
188         0x007C1E24, 0x007D0C69,
189         0x007E0955, 0x007F03C9,
190         0x008003E9, 0x00810975,
191         0x00820C49, 0x00831E04,
192         0x00840C48, 0x00851E05,
193         0x008617A6, 0x008701C5,
194         0x008800C6, 0x00891B08,
195         0x008A0E06, 0x008B0666,
196         0x008C0E08, 0x008D0668,
197         0x008E1D7C, 0x008F0CE5,
198         0x00900C45, 0x00911E08,
199         0x009217A9, 0x009301C4,
200         0x009417AA, 0x009501C9,
201         0x00960169, 0x0097588A,
202         0x00981888, 0x00990066,
203         0x009A0709, 0x009B07A8,
204         0x009C0704, 0x009D07A6,
205         0x009E16E6, 0x009F0345,
206         0x00A000C9, 0x00A11B05,
207         0x00A20E09, 0x00A30669,
208         0x00A41885, 0x00A50065,
209         0x00A60706, 0x00A707A5,
210         0x00A803A9, 0x00A90189,
211         0x00AA0029, 0x00AB0889,
212         0x00AC0744, 0x00AD06E9,
213         0x00AE0B06, 0x00AF0229,
214         0x00B00E05, 0x00B10665,
215         0x00B21974, 0x00B30CE8,
216         0x00B4070A, 0x00B507A9,
217         0x00B616E9, 0x00B70348,
218         0x00B8074A, 0x00B906E6,
219         0x00BA0B09, 0x00BB0226,
220         0x00BC1CE4, 0x00BD0D7D,
221         0x00BE0269, 0x00BF08C9,
222         0x00C000CA, 0x00C11B04,
223         0x00C21884, 0x00C3006A,
224         0x00C40E04, 0x00C50664,
225         0x00C60708, 0x00C707AA,
226         0x00C803A8, 0x00C90184,
227         0x00CA0749, 0x00CB06E4,
228         0x00CC0020, 0x00CD0888,
229         0x00CE0B08, 0x00CF0224,
230         0x00D00E0A, 0x00D1066A,
231         0x00D20705, 0x00D307A4,
232         0x00D41D78, 0x00D50CE9,
233         0x00D616EA, 0x00D70349,
234         0x00D80745, 0x00D906E8,
235         0x00DA1CE9, 0x00DB0D75,
236         0x00DC0B04, 0x00DD0228,
237         0x00DE0268, 0x00DF08C8,
238         0x00E003A5, 0x00E10185,
239         0x00E20746, 0x00E306EA,
240         0x00E40748, 0x00E506E5,
241         0x00E61CE8, 0x00E70D79,
242         0x00E81D74, 0x00E95CE6,
243         0x00EA02E9, 0x00EB0849,
244         0x00EC02E8, 0x00ED0848,
245         0x00EE0086, 0x00EF0A08,
246         0x00F00021, 0x00F10885,
247         0x00F20B05, 0x00F3022A,
248         0x00F40B0A, 0x00F50225,
249         0x00F60265, 0x00F708C5,
250         0x00F802E5, 0x00F90845,
251         0x00FA0089, 0x00FB0A09,
252         0x00FC008A, 0x00FD0A0A,
253         0x00FE02A9, 0x00FF0062,
254     };
255
256     if (!hbmMask)
257         return BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
258
259     hbrMask = CreatePatternBrush(hbmMask);
260     hbrDst = SelectObject(hdcDest, GetStockObject(NULL_BRUSH));
261
262     /* make bitmap */
263     hDC1 = CreateCompatibleDC(hdcDest);
264     hBitmap1 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
265     hOldBitmap1 = SelectObject(hDC1, hBitmap1);
266
267     /* draw using bkgnd rop */
268     BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
269     hbrTmp = SelectObject(hDC1, hbrDst);
270     BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, BKGND_ROP3(dwRop));
271     SelectObject(hDC1, hbrTmp);
272
273     /* make bitmap */
274     hDC2 = CreateCompatibleDC(hdcDest);
275     hBitmap2 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
276     hOldBitmap2 = SelectObject(hDC2, hBitmap2);
277
278     /* draw using foregnd rop */
279     BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
280     hbrTmp = SelectObject(hDC2, hbrDst);
281     BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
282
283     /* combine both using the mask as a pattern brush */
284     SelectObject(hDC2, hbrMask);
285     BitBlt(hDC2, 0, 0, nWidth, nHeight, hDC1, 0, 0, 0xac0744 ); /* (D & P) | (S & ~P) */ 
286     SelectObject(hDC2, hbrTmp);
287
288     /* blit to dst */
289     BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hDC2, 0, 0, SRCCOPY);
290
291     /* restore all objects */
292     SelectObject(hdcDest, hbrDst);
293     SelectObject(hDC1, hOldBitmap1);
294     SelectObject(hDC2, hOldBitmap2);
295
296     /* delete all temp objects */
297     DeleteObject(hBitmap1);
298     DeleteObject(hBitmap1);
299     DeleteObject(hbrMask);
300
301     DeleteDC(hDC1);
302     DeleteDC(hDC2);
303
304     return TRUE;
305 }
306
307 /******************************************************************************
308  *           GdiTransparentBlt [GDI32.@]
309  */
310 BOOL WINAPI GdiTransparentBlt( HDC hdcDest, int xDest, int yDest, int widthDest, int heightDest,
311                             HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
312                             UINT crTransparent )
313 {
314     BOOL ret = FALSE;
315     HDC hdcWork;
316     HBITMAP bmpWork;
317     HGDIOBJ oldWork;
318     HDC hdcMask = NULL;
319     HBITMAP bmpMask = NULL;
320     HBITMAP oldMask = NULL;
321     COLORREF oldBackground;
322     COLORREF oldForeground;
323     int oldStretchMode;
324
325     if(widthDest < 0 || heightDest < 0 || widthSrc < 0 || heightSrc < 0) {
326         TRACE("Can not mirror\n");
327         return FALSE;
328     }
329
330     oldBackground = SetBkColor(hdcDest, RGB(255,255,255));
331     oldForeground = SetTextColor(hdcDest, RGB(0,0,0));
332
333     /* Stretch bitmap */
334     oldStretchMode = GetStretchBltMode(hdcSrc);
335     if(oldStretchMode == BLACKONWHITE || oldStretchMode == WHITEONBLACK)
336         SetStretchBltMode(hdcSrc, COLORONCOLOR);
337     hdcWork = CreateCompatibleDC(hdcDest);
338     bmpWork = CreateCompatibleBitmap(hdcDest, widthDest, heightDest);
339     oldWork = SelectObject(hdcWork, bmpWork);
340     if(!StretchBlt(hdcWork, 0, 0, widthDest, heightDest, hdcSrc, xSrc, ySrc, widthSrc, heightSrc, SRCCOPY)) {
341         TRACE("Failed to stretch\n");
342         goto error;
343     }
344     SetBkColor(hdcWork, crTransparent);
345
346     /* Create mask */
347     hdcMask = CreateCompatibleDC(hdcDest);
348     bmpMask = CreateCompatibleBitmap(hdcMask, widthDest, heightDest);
349     oldMask = SelectObject(hdcMask, bmpMask);
350     if(!BitBlt(hdcMask, 0, 0, widthDest, heightDest, hdcWork, 0, 0, SRCCOPY)) {
351         TRACE("Failed to create mask\n");
352         goto error;
353     }
354
355     /* Replace transparent color with black */
356     SetBkColor(hdcWork, RGB(0,0,0));
357     SetTextColor(hdcWork, RGB(255,255,255));
358     if(!BitBlt(hdcWork, 0, 0, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
359         TRACE("Failed to mask out background\n");
360         goto error;
361     }
362
363     /* Replace non-transparent area on destination with black */
364     if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
365         TRACE("Failed to clear destination area\n");
366         goto error;
367     }
368
369     /* Draw the image */
370     if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcWork, 0, 0, SRCPAINT)) {
371         TRACE("Failed to paint image\n");
372         goto error;
373     }
374
375     ret = TRUE;
376 error:
377     SetStretchBltMode(hdcSrc, oldStretchMode);
378     SetBkColor(hdcDest, oldBackground);
379     SetTextColor(hdcDest, oldForeground);
380     if(hdcWork) {
381         SelectObject(hdcWork, oldWork);
382         DeleteDC(hdcWork);
383     }
384     if(bmpWork) DeleteObject(bmpWork);
385     if(hdcMask) {
386         SelectObject(hdcMask, oldMask);
387         DeleteDC(hdcMask);
388     }
389     if(bmpMask) DeleteObject(bmpMask);
390     return ret;
391 }
392
393 /******************************************************************************
394  *           GdiAlphaBlend [GDI32.@]
395  */
396 BOOL WINAPI GdiAlphaBlend(HDC hdcDst, int xDst, int yDst, int widthDst, int heightDst,
397                           HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
398                           BLENDFUNCTION blendFunction)
399 {
400     BOOL ret = FALSE;
401     DC *dcDst, *dcSrc;
402
403     if ((dcSrc = DC_GetDCUpdate( hdcSrc ))) GDI_ReleaseObj( hdcSrc );
404     /* FIXME: there is a race condition here */
405     if ((dcDst = DC_GetDCUpdate( hdcDst )))
406     {
407         dcSrc = DC_GetDCPtr( hdcSrc );
408         TRACE("%p %d,%d %dx%d -> %p %d,%d %dx%d op=%02x flags=%02x srcconstalpha=%02x alphafmt=%02x\n",
409               hdcSrc, xSrc, ySrc, widthSrc, heightSrc,
410               hdcDst, xDst, yDst, widthDst, heightDst,
411               blendFunction.BlendOp, blendFunction.BlendFlags,
412               blendFunction.SourceConstantAlpha, blendFunction.AlphaFormat);
413         if (dcDst->funcs->pAlphaBlend)
414             ret = dcDst->funcs->pAlphaBlend( dcDst->physDev, xDst, yDst, widthDst, heightDst,
415                                              dcSrc ? dcSrc->physDev : NULL,
416                                              xSrc, ySrc, widthSrc, heightSrc, blendFunction );
417         if (dcSrc) GDI_ReleaseObj( hdcSrc );
418         GDI_ReleaseObj( hdcDst );
419     }
420     return ret;
421 }
422
423 /*********************************************************************
424  *      PlgBlt [GDI32.@]
425  *
426  */
427 BOOL WINAPI PlgBlt( HDC hdcDest, const POINT *lpPoint,
428                         HDC hdcSrc, INT nXDest, INT nYDest, INT nWidth,
429                         INT nHeight, HBITMAP hbmMask, INT xMask, INT yMask)
430 {
431     FIXME("PlgBlt, stub\n");
432         return 1;
433 }