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