2 * GDI bit-blit operations
4 * Copyright 1993, 1994 Alexandre Julliard
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.
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.
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
33 #include "gdi_private.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(bitblt);
38 static inline BOOL rop_uses_src( DWORD rop )
40 return ((rop >> 2) & 0x330000) != (rop & 0x330000);
43 /***********************************************************************
46 BOOL WINAPI PatBlt( HDC hdc, INT left, INT top, INT width, INT height, DWORD rop)
51 TRACE("%p %d,%d %dx%d %06x\n", hdc, left, top, width, height, rop );
53 if (rop_uses_src( rop )) return FALSE;
54 if ((dc = get_dc_ptr( hdc )))
56 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPatBlt );
58 bRet = physdev->funcs->pPatBlt( physdev, left, top, width, height, rop );
65 /***********************************************************************
68 BOOL WINAPI BitBlt( HDC hdcDst, INT xDst, INT yDst, INT width,
69 INT height, HDC hdcSrc, INT xSrc, INT ySrc, DWORD rop )
71 if (!rop_uses_src( rop )) return PatBlt( hdcDst, xDst, yDst, width, height, rop );
72 else return StretchBlt( hdcDst, xDst, yDst, width, height,
73 hdcSrc, xSrc, ySrc, width, height, rop );
77 /***********************************************************************
78 * StretchBlt (GDI32.@)
80 BOOL WINAPI StretchBlt( HDC hdcDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
81 HDC hdcSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc, DWORD rop )
86 if (!rop_uses_src( rop )) return PatBlt( hdcDst, xDst, yDst, widthDst, heightDst, rop );
88 TRACE("%p %d,%d %dx%d -> %p %d,%d %dx%d rop=%06x\n",
89 hdcSrc, xSrc, ySrc, widthSrc, heightSrc,
90 hdcDst, xDst, yDst, widthDst, heightDst, rop );
93 if (!(dcDst = get_dc_ptr( hdcDst ))) return FALSE;
96 if (dcDst->funcs->pStretchBlt)
98 if ((dcSrc = get_dc_ptr( hdcSrc )))
102 ret = dcDst->funcs->pStretchBlt( dcDst->physDev, xDst, yDst, widthDst, heightDst,
103 dcSrc->physDev, xSrc, ySrc, widthSrc, heightSrc,
105 release_dc_ptr( dcSrc );
107 release_dc_ptr( dcDst );
109 else if (dcDst->funcs->pStretchDIBits)
112 BITMAPINFOHEADER info_hdr;
120 pts[1].x = xSrc + widthSrc;
121 pts[1].y = ySrc + heightSrc;
122 LPtoDP(hdcSrc, pts, 2);
125 widthSrc = pts[1].x - pts[0].x;
126 heightSrc = pts[1].y - pts[0].y;
128 release_dc_ptr( dcDst );
130 if(GetObjectType( hdcSrc ) != OBJ_MEMDC) return FALSE;
132 GetObjectW(GetCurrentObject(hdcSrc, OBJ_BITMAP), sizeof(bm), &bm);
134 info_hdr.biSize = sizeof(info_hdr);
135 info_hdr.biWidth = bm.bmWidth;
136 info_hdr.biHeight = bm.bmHeight;
137 info_hdr.biPlanes = 1;
138 info_hdr.biBitCount = 32;
139 info_hdr.biCompression = BI_RGB;
140 info_hdr.biSizeImage = 0;
141 info_hdr.biXPelsPerMeter = 0;
142 info_hdr.biYPelsPerMeter = 0;
143 info_hdr.biClrUsed = 0;
144 info_hdr.biClrImportant = 0;
146 if(!(bits = HeapAlloc(GetProcessHeap(), 0, bm.bmHeight * bm.bmWidth * 4)))
149 /* Select out the src bitmap before calling GetDIBits */
150 hbm = SelectObject(hdcSrc, GetStockObject(DEFAULT_BITMAP));
151 GetDIBits(hdcSrc, hbm, 0, bm.bmHeight, bits, (BITMAPINFO*)&info_hdr, DIB_RGB_COLORS);
152 SelectObject(hdcSrc, hbm);
154 lines = StretchDIBits(hdcDst, xDst, yDst, widthDst, heightDst, xSrc, bm.bmHeight - heightSrc - ySrc,
155 widthSrc, heightSrc, bits, (BITMAPINFO*)&info_hdr, DIB_RGB_COLORS, rop);
157 HeapFree(GetProcessHeap(), 0, bits);
158 return (lines == heightSrc);
160 else release_dc_ptr( dcDst );
165 #define FRGND_ROP3(ROP4) ((ROP4) & 0x00FFFFFF)
166 #define BKGND_ROP3(ROP4) (ROP3Table[((ROP4)>>24) & 0xFF])
168 /***********************************************************************
171 BOOL WINAPI MaskBlt(HDC hdcDest, INT nXDest, INT nYDest,
172 INT nWidth, INT nHeight, HDC hdcSrc,
173 INT nXSrc, INT nYSrc, HBITMAP hbmMask,
174 INT xMask, INT yMask, DWORD dwRop)
176 HBITMAP hBitmap1, hOldBitmap1, hBitmap2, hOldBitmap2;
178 HBRUSH hbrMask, hbrDst, hbrTmp;
180 static const DWORD ROP3Table[256] =
182 0x00000042, 0x00010289,
183 0x00020C89, 0x000300AA,
184 0x00040C88, 0x000500A9,
185 0x00060865, 0x000702C5,
186 0x00080F08, 0x00090245,
187 0x000A0329, 0x000B0B2A,
188 0x000C0324, 0x000D0B25,
189 0x000E08A5, 0x000F0001,
190 0x00100C85, 0x001100A6,
191 0x00120868, 0x001302C8,
192 0x00140869, 0x001502C9,
193 0x00165CCA, 0x00171D54,
194 0x00180D59, 0x00191CC8,
195 0x001A06C5, 0x001B0768,
196 0x001C06CA, 0x001D0766,
197 0x001E01A5, 0x001F0385,
198 0x00200F09, 0x00210248,
199 0x00220326, 0x00230B24,
200 0x00240D55, 0x00251CC5,
201 0x002606C8, 0x00271868,
202 0x00280369, 0x002916CA,
203 0x002A0CC9, 0x002B1D58,
204 0x002C0784, 0x002D060A,
205 0x002E064A, 0x002F0E2A,
206 0x0030032A, 0x00310B28,
207 0x00320688, 0x00330008,
208 0x003406C4, 0x00351864,
209 0x003601A8, 0x00370388,
210 0x0038078A, 0x00390604,
211 0x003A0644, 0x003B0E24,
212 0x003C004A, 0x003D18A4,
213 0x003E1B24, 0x003F00EA,
214 0x00400F0A, 0x00410249,
215 0x00420D5D, 0x00431CC4,
216 0x00440328, 0x00450B29,
217 0x004606C6, 0x0047076A,
218 0x00480368, 0x004916C5,
219 0x004A0789, 0x004B0605,
220 0x004C0CC8, 0x004D1954,
221 0x004E0645, 0x004F0E25,
222 0x00500325, 0x00510B26,
223 0x005206C9, 0x00530764,
224 0x005408A9, 0x00550009,
225 0x005601A9, 0x00570389,
226 0x00580785, 0x00590609,
227 0x005A0049, 0x005B18A9,
228 0x005C0649, 0x005D0E29,
229 0x005E1B29, 0x005F00E9,
230 0x00600365, 0x006116C6,
231 0x00620786, 0x00630608,
232 0x00640788, 0x00650606,
233 0x00660046, 0x006718A8,
234 0x006858A6, 0x00690145,
235 0x006A01E9, 0x006B178A,
236 0x006C01E8, 0x006D1785,
237 0x006E1E28, 0x006F0C65,
238 0x00700CC5, 0x00711D5C,
239 0x00720648, 0x00730E28,
240 0x00740646, 0x00750E26,
241 0x00761B28, 0x007700E6,
242 0x007801E5, 0x00791786,
243 0x007A1E29, 0x007B0C68,
244 0x007C1E24, 0x007D0C69,
245 0x007E0955, 0x007F03C9,
246 0x008003E9, 0x00810975,
247 0x00820C49, 0x00831E04,
248 0x00840C48, 0x00851E05,
249 0x008617A6, 0x008701C5,
250 0x008800C6, 0x00891B08,
251 0x008A0E06, 0x008B0666,
252 0x008C0E08, 0x008D0668,
253 0x008E1D7C, 0x008F0CE5,
254 0x00900C45, 0x00911E08,
255 0x009217A9, 0x009301C4,
256 0x009417AA, 0x009501C9,
257 0x00960169, 0x0097588A,
258 0x00981888, 0x00990066,
259 0x009A0709, 0x009B07A8,
260 0x009C0704, 0x009D07A6,
261 0x009E16E6, 0x009F0345,
262 0x00A000C9, 0x00A11B05,
263 0x00A20E09, 0x00A30669,
264 0x00A41885, 0x00A50065,
265 0x00A60706, 0x00A707A5,
266 0x00A803A9, 0x00A90189,
267 0x00AA0029, 0x00AB0889,
268 0x00AC0744, 0x00AD06E9,
269 0x00AE0B06, 0x00AF0229,
270 0x00B00E05, 0x00B10665,
271 0x00B21974, 0x00B30CE8,
272 0x00B4070A, 0x00B507A9,
273 0x00B616E9, 0x00B70348,
274 0x00B8074A, 0x00B906E6,
275 0x00BA0B09, 0x00BB0226,
276 0x00BC1CE4, 0x00BD0D7D,
277 0x00BE0269, 0x00BF08C9,
278 0x00C000CA, 0x00C11B04,
279 0x00C21884, 0x00C3006A,
280 0x00C40E04, 0x00C50664,
281 0x00C60708, 0x00C707AA,
282 0x00C803A8, 0x00C90184,
283 0x00CA0749, 0x00CB06E4,
284 0x00CC0020, 0x00CD0888,
285 0x00CE0B08, 0x00CF0224,
286 0x00D00E0A, 0x00D1066A,
287 0x00D20705, 0x00D307A4,
288 0x00D41D78, 0x00D50CE9,
289 0x00D616EA, 0x00D70349,
290 0x00D80745, 0x00D906E8,
291 0x00DA1CE9, 0x00DB0D75,
292 0x00DC0B04, 0x00DD0228,
293 0x00DE0268, 0x00DF08C8,
294 0x00E003A5, 0x00E10185,
295 0x00E20746, 0x00E306EA,
296 0x00E40748, 0x00E506E5,
297 0x00E61CE8, 0x00E70D79,
298 0x00E81D74, 0x00E95CE6,
299 0x00EA02E9, 0x00EB0849,
300 0x00EC02E8, 0x00ED0848,
301 0x00EE0086, 0x00EF0A08,
302 0x00F00021, 0x00F10885,
303 0x00F20B05, 0x00F3022A,
304 0x00F40B0A, 0x00F50225,
305 0x00F60265, 0x00F708C5,
306 0x00F802E5, 0x00F90845,
307 0x00FA0089, 0x00FB0A09,
308 0x00FC008A, 0x00FD0A0A,
309 0x00FE02A9, 0x00FF0062,
313 return BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
315 hbrMask = CreatePatternBrush(hbmMask);
316 hbrDst = SelectObject(hdcDest, GetStockObject(NULL_BRUSH));
319 hDC1 = CreateCompatibleDC(hdcDest);
320 hBitmap1 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
321 hOldBitmap1 = SelectObject(hDC1, hBitmap1);
323 /* draw using bkgnd rop */
324 BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
325 hbrTmp = SelectObject(hDC1, hbrDst);
326 BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, BKGND_ROP3(dwRop));
327 SelectObject(hDC1, hbrTmp);
330 hDC2 = CreateCompatibleDC(hdcDest);
331 hBitmap2 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
332 hOldBitmap2 = SelectObject(hDC2, hBitmap2);
334 /* draw using foregnd rop */
335 BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
336 hbrTmp = SelectObject(hDC2, hbrDst);
337 BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
339 /* combine both using the mask as a pattern brush */
340 SelectObject(hDC2, hbrMask);
341 BitBlt(hDC2, 0, 0, nWidth, nHeight, hDC1, 0, 0, 0xac0744 ); /* (D & P) | (S & ~P) */
342 SelectObject(hDC2, hbrTmp);
345 BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hDC2, 0, 0, SRCCOPY);
347 /* restore all objects */
348 SelectObject(hdcDest, hbrDst);
349 SelectObject(hDC1, hOldBitmap1);
350 SelectObject(hDC2, hOldBitmap2);
352 /* delete all temp objects */
353 DeleteObject(hBitmap1);
354 DeleteObject(hBitmap2);
355 DeleteObject(hbrMask);
363 /******************************************************************************
364 * GdiTransparentBlt [GDI32.@]
366 BOOL WINAPI GdiTransparentBlt( HDC hdcDest, int xDest, int yDest, int widthDest, int heightDest,
367 HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
375 HBITMAP bmpMask = NULL;
376 HBITMAP oldMask = NULL;
377 COLORREF oldBackground;
378 COLORREF oldForeground;
381 if(widthDest < 0 || heightDest < 0 || widthSrc < 0 || heightSrc < 0) {
382 TRACE("Cannot mirror\n");
386 oldBackground = SetBkColor(hdcDest, RGB(255,255,255));
387 oldForeground = SetTextColor(hdcDest, RGB(0,0,0));
390 oldStretchMode = GetStretchBltMode(hdcSrc);
391 if(oldStretchMode == BLACKONWHITE || oldStretchMode == WHITEONBLACK)
392 SetStretchBltMode(hdcSrc, COLORONCOLOR);
393 hdcWork = CreateCompatibleDC(hdcDest);
394 bmpWork = CreateCompatibleBitmap(hdcDest, widthDest, heightDest);
395 oldWork = SelectObject(hdcWork, bmpWork);
396 if(!StretchBlt(hdcWork, 0, 0, widthDest, heightDest, hdcSrc, xSrc, ySrc, widthSrc, heightSrc, SRCCOPY)) {
397 TRACE("Failed to stretch\n");
400 SetBkColor(hdcWork, crTransparent);
403 hdcMask = CreateCompatibleDC(hdcDest);
404 bmpMask = CreateCompatibleBitmap(hdcMask, widthDest, heightDest);
405 oldMask = SelectObject(hdcMask, bmpMask);
406 if(!BitBlt(hdcMask, 0, 0, widthDest, heightDest, hdcWork, 0, 0, SRCCOPY)) {
407 TRACE("Failed to create mask\n");
411 /* Replace transparent color with black */
412 SetBkColor(hdcWork, RGB(0,0,0));
413 SetTextColor(hdcWork, RGB(255,255,255));
414 if(!BitBlt(hdcWork, 0, 0, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
415 TRACE("Failed to mask out background\n");
419 /* Replace non-transparent area on destination with black */
420 if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
421 TRACE("Failed to clear destination area\n");
426 if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcWork, 0, 0, SRCPAINT)) {
427 TRACE("Failed to paint image\n");
433 SetStretchBltMode(hdcSrc, oldStretchMode);
434 SetBkColor(hdcDest, oldBackground);
435 SetTextColor(hdcDest, oldForeground);
437 SelectObject(hdcWork, oldWork);
440 if(bmpWork) DeleteObject(bmpWork);
442 SelectObject(hdcMask, oldMask);
445 if(bmpMask) DeleteObject(bmpMask);
449 /******************************************************************************
450 * GdiAlphaBlend [GDI32.@]
452 BOOL WINAPI GdiAlphaBlend(HDC hdcDst, int xDst, int yDst, int widthDst, int heightDst,
453 HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
454 BLENDFUNCTION blendFunction)
459 dcSrc = get_dc_ptr( hdcSrc );
460 if (!dcSrc) return FALSE;
462 if ((dcDst = get_dc_ptr( hdcDst )))
466 TRACE("%p %d,%d %dx%d -> %p %d,%d %dx%d op=%02x flags=%02x srcconstalpha=%02x alphafmt=%02x\n",
467 hdcSrc, xSrc, ySrc, widthSrc, heightSrc,
468 hdcDst, xDst, yDst, widthDst, heightDst,
469 blendFunction.BlendOp, blendFunction.BlendFlags,
470 blendFunction.SourceConstantAlpha, blendFunction.AlphaFormat);
471 if (dcDst->funcs->pAlphaBlend)
472 ret = dcDst->funcs->pAlphaBlend( dcDst->physDev, xDst, yDst, widthDst, heightDst,
473 dcSrc->physDev, xSrc, ySrc, widthSrc, heightSrc,
475 release_dc_ptr( dcDst );
477 release_dc_ptr( dcSrc );
481 /*********************************************************************
485 BOOL WINAPI PlgBlt( HDC hdcDest, const POINT *lpPoint,
486 HDC hdcSrc, INT nXSrc, INT nYSrc, INT nWidth,
487 INT nHeight, HBITMAP hbmMask, INT xMask, INT yMask)
490 /* parallelogram coords */
499 /* save actual mode, set GM_ADVANCED */
500 oldgMode = SetGraphicsMode(hdcDest,GM_ADVANCED);
504 memcpy(plg,lpPoint,sizeof(POINT)*3);
507 rect[1].x = nXSrc + nWidth;
510 rect[2].y = nYSrc + nHeight;
511 /* calc XFORM matrix to transform hdcDest -> hdcSrc (parallelogram to rectangle) */
513 det = rect[1].x*(rect[2].y - rect[0].y) - rect[2].x*(rect[1].y - rect[0].y) - rect[0].x*(rect[2].y - rect[1].y);
515 if (fabs(det) < 1e-5)
517 SetGraphicsMode(hdcDest,oldgMode);
521 TRACE("hdcSrc=%p %d,%d,%dx%d -> hdcDest=%p %d,%d,%d,%d,%d,%d\n",
522 hdcSrc, nXSrc, nYSrc, nWidth, nHeight, hdcDest, plg[0].x, plg[0].y, plg[1].x, plg[1].y, plg[2].x, plg[2].y);
525 xf.eM11 = (plg[1].x*(rect[2].y - rect[0].y) - plg[2].x*(rect[1].y - rect[0].y) - plg[0].x*(rect[2].y - rect[1].y)) / det;
526 xf.eM21 = (rect[1].x*(plg[2].x - plg[0].x) - rect[2].x*(plg[1].x - plg[0].x) - rect[0].x*(plg[2].x - plg[1].x)) / det;
527 xf.eDx = (rect[0].x*(rect[1].y*plg[2].x - rect[2].y*plg[1].x) -
528 rect[1].x*(rect[0].y*plg[2].x - rect[2].y*plg[0].x) +
529 rect[2].x*(rect[0].y*plg[1].x - rect[1].y*plg[0].x)
533 xf.eM12 = (plg[1].y*(rect[2].y - rect[0].y) - plg[2].y*(rect[1].y - rect[0].y) - plg[0].y*(rect[2].y - rect[1].y)) / det;
534 xf.eM22 = (plg[1].x*(rect[2].y - rect[0].y) - plg[2].x*(rect[1].y - rect[0].y) - plg[0].x*(rect[2].y - rect[1].y)) / det;
535 xf.eDy = (rect[0].x*(rect[1].y*plg[2].y - rect[2].y*plg[1].y) -
536 rect[1].x*(rect[0].y*plg[2].y - rect[2].y*plg[0].y) +
537 rect[2].x*(rect[0].y*plg[1].y - rect[1].y*plg[0].y)
540 GetWorldTransform(hdcSrc,&SrcXf);
541 CombineTransform(&xf,&xf,&SrcXf);
543 /* save actual dest transform */
544 GetWorldTransform(hdcDest,&oldDestXf);
546 SetWorldTransform(hdcDest,&xf);
547 /* now destination and source DCs use same coords */
548 MaskBlt(hdcDest,nXSrc,nYSrc,nWidth,nHeight,
552 /* restore dest DC */
553 SetWorldTransform(hdcDest,&oldDestXf);
554 SetGraphicsMode(hdcDest,oldgMode);