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