[WIN32K]
[reactos.git] / reactos / subsystems / win32 / win32k / objects / bitblt.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 /* $Id: bitmaps.c 28300 2007-08-12 15:20:09Z tkreuzer $ */
20
21 #include <win32k.h>
22
23 #define NDEBUG
24 #include <debug.h>
25
26
27
28 BOOL APIENTRY
29 NtGdiAlphaBlend(
30 HDC hDCDest,
31 LONG XOriginDest,
32 LONG YOriginDest,
33 LONG WidthDest,
34 LONG HeightDest,
35 HDC hDCSrc,
36 LONG XOriginSrc,
37 LONG YOriginSrc,
38 LONG WidthSrc,
39 LONG HeightSrc,
40 BLENDFUNCTION BlendFunc,
41 HANDLE hcmXform)
42 {
43 PDC DCDest;
44 PDC DCSrc;
45 SURFACE *BitmapDest, *BitmapSrc;
46 RECTL DestRect, SourceRect;
47 BOOL bResult;
48 EXLATEOBJ exlo;
49 BLENDOBJ BlendObj;
50 BlendObj.BlendFunction = BlendFunc;
51
52 if (WidthDest < 0 || HeightDest < 0 || WidthSrc < 0 || HeightSrc < 0)
53 {
54 SetLastWin32Error(ERROR_INVALID_PARAMETER);
55 return FALSE;
56 }
57
58 DCDest = DC_LockDc(hDCDest);
59 if (NULL == DCDest)
60 {
61 DPRINT1("Invalid destination dc handle (0x%08x) passed to NtGdiAlphaBlend\n", hDCDest);
62 SetLastWin32Error(ERROR_INVALID_HANDLE);
63 return FALSE;
64 }
65
66 if (DCDest->dctype == DC_TYPE_INFO)
67 {
68 DC_UnlockDc(DCDest);
69 /* Yes, Windows really returns TRUE in this case */
70 return TRUE;
71 }
72
73 if (hDCSrc != hDCDest)
74 {
75 DCSrc = DC_LockDc(hDCSrc);
76 if (NULL == DCSrc)
77 {
78 DC_UnlockDc(DCDest);
79 DPRINT1("Invalid source dc handle (0x%08x) passed to NtGdiAlphaBlend\n", hDCSrc);
80 SetLastWin32Error(ERROR_INVALID_HANDLE);
81 return FALSE;
82 }
83
84 if (DCSrc->dctype == DC_TYPE_INFO)
85 {
86 DC_UnlockDc(DCSrc);
87 DC_UnlockDc(DCDest);
88 /* Yes, Windows really returns TRUE in this case */
89 return TRUE;
90 }
91 }
92 else
93 {
94 DCSrc = DCDest;
95 }
96
97 DestRect.left = XOriginDest;
98 DestRect.top = YOriginDest;
99 DestRect.right = XOriginDest + WidthDest;
100 DestRect.bottom = YOriginDest + HeightDest;
101 IntLPtoDP(DCDest, (LPPOINT)&DestRect, 2);
102
103 DestRect.left += DCDest->ptlDCOrig.x;
104 DestRect.top += DCDest->ptlDCOrig.y;
105 DestRect.right += DCDest->ptlDCOrig.x;
106 DestRect.bottom += DCDest->ptlDCOrig.y;
107
108 SourceRect.left = XOriginSrc;
109 SourceRect.top = YOriginSrc;
110 SourceRect.right = XOriginSrc + WidthSrc;
111 SourceRect.bottom = YOriginSrc + HeightSrc;
112 IntLPtoDP(DCSrc, (LPPOINT)&SourceRect, 2);
113
114 SourceRect.left += DCSrc->ptlDCOrig.x;
115 SourceRect.top += DCSrc->ptlDCOrig.y;
116 SourceRect.right += DCSrc->ptlDCOrig.x;
117 SourceRect.bottom += DCSrc->ptlDCOrig.y;
118
119 if (!DestRect.right ||
120 !DestRect.bottom ||
121 !SourceRect.right ||
122 !SourceRect.bottom)
123 {
124 if (hDCSrc != hDCDest)
125 DC_UnlockDc(DCSrc);
126 DC_UnlockDc(DCDest);
127 return TRUE;
128 }
129
130 /* Determine surfaces to be used in the bitblt */
131 BitmapDest = DCDest->dclevel.pSurface;
132 if (!BitmapDest)
133 {
134 if (hDCSrc != hDCDest)
135 DC_UnlockDc(DCSrc);
136 DC_UnlockDc(DCDest);
137 return FALSE;
138 }
139
140 BitmapSrc = DCSrc->dclevel.pSurface;
141 if (!BitmapSrc)
142 {
143 if (hDCSrc != hDCDest)
144 DC_UnlockDc(DCSrc);
145 DC_UnlockDc(DCDest);
146 return FALSE;
147 }
148
149 /* Create the XLATEOBJ. */
150 EXLATEOBJ_vInitXlateFromDCs(&exlo, DCSrc, DCDest);
151
152 /* Perform the alpha blend operation */
153 bResult = IntEngAlphaBlend(&BitmapDest->SurfObj,
154 &BitmapSrc->SurfObj,
155 DCDest->rosdc.CombinedClip,
156 &exlo.xlo,
157 &DestRect,
158 &SourceRect,
159 &BlendObj);
160
161 EXLATEOBJ_vCleanup(&exlo);
162 DC_UnlockDc(DCDest);
163 if (hDCSrc != hDCDest)
164 DC_UnlockDc(DCSrc);
165
166 return bResult;
167 }
168
169 BOOL APIENTRY
170 NtGdiBitBlt(
171 HDC hDCDest,
172 INT XDest,
173 INT YDest,
174 INT Width,
175 INT Height,
176 HDC hDCSrc,
177 INT XSrc,
178 INT YSrc,
179 DWORD ROP,
180 IN DWORD crBackColor,
181 IN FLONG fl)
182 {
183 PDC DCDest;
184 PDC DCSrc = NULL;
185 PDC_ATTR pdcattr = NULL;
186 SURFACE *BitmapDest, *BitmapSrc = NULL;
187 RECTL DestRect;
188 POINTL SourcePoint;
189 BOOL Status = FALSE;
190 EXLATEOBJ exlo;
191 XLATEOBJ *XlateObj = NULL;
192 BOOL UsesSource = ROP3_USES_SOURCE(ROP);
193
194 DCDest = DC_LockDc(hDCDest);
195 if (NULL == DCDest)
196 {
197 DPRINT("Invalid destination dc handle (0x%08x) passed to NtGdiBitBlt\n", hDCDest);
198 return FALSE;
199 }
200
201 if (DCDest->dctype == DC_TYPE_INFO)
202 {
203 DC_UnlockDc(DCDest);
204 /* Yes, Windows really returns TRUE in this case */
205 return TRUE;
206 }
207
208 if (UsesSource)
209 {
210 if (hDCSrc != hDCDest)
211 {
212 DCSrc = DC_LockDc(hDCSrc);
213 if (NULL == DCSrc)
214 {
215 DC_UnlockDc(DCDest);
216 DPRINT("Invalid source dc handle (0x%08x) passed to NtGdiBitBlt\n", hDCSrc);
217 return FALSE;
218 }
219 if (DCSrc->dctype == DC_TYPE_INFO)
220 {
221 DC_UnlockDc(DCSrc);
222 DC_UnlockDc(DCDest);
223 /* Yes, Windows really returns TRUE in this case */
224 return TRUE;
225 }
226 }
227 else
228 {
229 DCSrc = DCDest;
230 }
231 }
232
233 pdcattr = DCDest->pdcattr;
234
235 if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
236 DC_vUpdateFillBrush(DCDest);
237
238 DestRect.left = XDest;
239 DestRect.top = YDest;
240 DestRect.right = XDest+Width;
241 DestRect.bottom = YDest+Height;
242 IntLPtoDP(DCDest, (LPPOINT)&DestRect, 2);
243
244 DestRect.left += DCDest->ptlDCOrig.x;
245 DestRect.top += DCDest->ptlDCOrig.y;
246 DestRect.right += DCDest->ptlDCOrig.x;
247 DestRect.bottom += DCDest->ptlDCOrig.y;
248
249 SourcePoint.x = XSrc;
250 SourcePoint.y = YSrc;
251
252 if (UsesSource)
253 {
254 IntLPtoDP(DCSrc, (LPPOINT)&SourcePoint, 1);
255
256 SourcePoint.x += DCSrc->ptlDCOrig.x;
257 SourcePoint.y += DCSrc->ptlDCOrig.y;
258 }
259
260 /* Determine surfaces to be used in the bitblt */
261 BitmapDest = DCDest->dclevel.pSurface;
262 if (!BitmapDest)
263 goto cleanup;
264
265 if (UsesSource)
266 {
267 {
268 BitmapSrc = DCSrc->dclevel.pSurface;
269 if (!BitmapSrc)
270 goto cleanup;
271 }
272 }
273
274 /* Create the XLATEOBJ. */
275 if (UsesSource)
276 {
277 EXLATEOBJ_vInitXlateFromDCs(&exlo, DCSrc, DCDest);
278 XlateObj = &exlo.xlo;
279 }
280
281 /* Perform the bitblt operation */
282 Status = IntEngBitBlt(&BitmapDest->SurfObj,
283 BitmapSrc ? &BitmapSrc->SurfObj : NULL,
284 NULL,
285 DCDest->rosdc.CombinedClip,
286 XlateObj,
287 &DestRect,
288 &SourcePoint,
289 NULL,
290 &DCDest->eboFill.BrushObject,
291 &DCDest->dclevel.pbrFill->ptOrigin,
292 ROP3_TO_ROP4(ROP));
293
294 if (UsesSource)
295 EXLATEOBJ_vCleanup(&exlo);
296 cleanup:
297 if (UsesSource && hDCSrc != hDCDest)
298 {
299 DC_UnlockDc(DCSrc);
300 }
301 DC_UnlockDc(DCDest);
302
303 return Status;
304 }
305
306 BOOL APIENTRY
307 NtGdiTransparentBlt(
308 HDC hdcDst,
309 INT xDst,
310 INT yDst,
311 INT cxDst,
312 INT cyDst,
313 HDC hdcSrc,
314 INT xSrc,
315 INT ySrc,
316 INT cxSrc,
317 INT cySrc,
318 COLORREF TransColor)
319 {
320 PDC DCDest, DCSrc;
321 RECTL rcDest, rcSrc;
322 SURFACE *BitmapDest, *BitmapSrc = NULL;
323 HPALETTE SourcePalette = 0, DestPalette = 0;
324 PPALETTE PalDestGDI, PalSourceGDI;
325 ULONG TransparentColor = 0;
326 BOOL Ret = FALSE;
327 EXLATEOBJ exlo;
328
329 if(!(DCDest = DC_LockDc(hdcDst)))
330 {
331 DPRINT1("Invalid destination dc handle (0x%08x) passed to NtGdiTransparentBlt\n", hdcDst);
332 SetLastWin32Error(ERROR_INVALID_HANDLE);
333 return FALSE;
334 }
335 if (DCDest->dctype == DC_TYPE_INFO)
336 {
337 DC_UnlockDc(DCDest);
338 /* Yes, Windows really returns TRUE in this case */
339 return TRUE;
340 }
341
342 if((hdcDst != hdcSrc) && !(DCSrc = DC_LockDc(hdcSrc)))
343 {
344 DC_UnlockDc(DCDest);
345 DPRINT1("Invalid source dc handle (0x%08x) passed to NtGdiTransparentBlt\n", hdcSrc);
346 SetLastWin32Error(ERROR_INVALID_HANDLE);
347 return FALSE;
348 }
349
350 if(hdcDst == hdcSrc)
351 {
352 DCSrc = DCDest;
353 }
354
355 if (DCSrc->dctype == DC_TYPE_INFO)
356 {
357 DC_UnlockDc(DCSrc);
358 if(hdcDst != hdcSrc)
359 {
360 DC_UnlockDc(DCDest);
361 }
362 /* Yes, Windows really returns TRUE in this case */
363 return TRUE;
364 }
365
366 BitmapDest = DCDest->dclevel.pSurface;
367 if (!BitmapDest)
368 {
369 goto done;
370 }
371
372 BitmapSrc = DCSrc->dclevel.pSurface;
373 if (!BitmapSrc)
374 {
375 goto done;
376 }
377
378 DestPalette = BitmapDest->hDIBPalette;
379 if (!DestPalette) DestPalette = pPrimarySurface->devinfo.hpalDefault;
380
381 SourcePalette = BitmapSrc->hDIBPalette;
382 if (!SourcePalette) SourcePalette = pPrimarySurface->devinfo.hpalDefault;
383
384 if(!(PalSourceGDI = PALETTE_LockPalette(SourcePalette)))
385 {
386 SetLastWin32Error(ERROR_INVALID_HANDLE);
387 goto done;
388 }
389 PALETTE_UnlockPalette(PalSourceGDI);
390
391 if(DestPalette != SourcePalette)
392 {
393 if (!(PalDestGDI = PALETTE_LockPalette(DestPalette)))
394 {
395 SetLastWin32Error(ERROR_INVALID_HANDLE);
396 goto done;
397 }
398 PALETTE_UnlockPalette(PalDestGDI);
399 }
400 else
401 {
402 PalDestGDI = PalSourceGDI;
403 }
404
405 /* Translate Transparent (RGB) Color to the source palette */
406 EXLATEOBJ_vInitialize(&exlo, &gpalRGB, PalSourceGDI, 0, 0, 0);
407 TransparentColor = XLATEOBJ_iXlate(&exlo.xlo, (ULONG)TransColor);
408 EXLATEOBJ_vCleanup(&exlo);
409
410 EXLATEOBJ_vInitialize(&exlo, PalSourceGDI, PalDestGDI, 0, 0, 0);
411
412 rcDest.left = xDst;
413 rcDest.top = yDst;
414 rcDest.right = rcDest.left + cxDst;
415 rcDest.bottom = rcDest.top + cyDst;
416 IntLPtoDP(DCDest, (LPPOINT)&rcDest, 2);
417
418 rcDest.left += DCDest->ptlDCOrig.x;
419 rcDest.top += DCDest->ptlDCOrig.y;
420 rcDest.right += DCDest->ptlDCOrig.x;
421 rcDest.bottom += DCDest->ptlDCOrig.y;
422
423 rcSrc.left = xSrc;
424 rcSrc.top = ySrc;
425 rcSrc.right = rcSrc.left + cxSrc;
426 rcSrc.bottom = rcSrc.top + cySrc;
427 IntLPtoDP(DCSrc, (LPPOINT)&rcSrc, 2);
428
429 rcSrc.left += DCSrc->ptlDCOrig.x;
430 rcSrc.top += DCSrc->ptlDCOrig.y;
431 rcSrc.right += DCSrc->ptlDCOrig.x;
432 rcSrc.bottom += DCSrc->ptlDCOrig.y;
433
434 Ret = IntEngTransparentBlt(&BitmapDest->SurfObj, &BitmapSrc->SurfObj,
435 DCDest->rosdc.CombinedClip, &exlo.xlo, &rcDest, &rcSrc,
436 TransparentColor, 0);
437
438 done:
439 DC_UnlockDc(DCSrc);
440 if(hdcDst != hdcSrc)
441 {
442 DC_UnlockDc(DCDest);
443 }
444 EXLATEOBJ_vCleanup(&exlo);
445 return Ret;
446 }
447
448 /***********************************************************************
449 * MaskBlt
450 * Ported from WINE by sedwards 11-4-03
451 *
452 * Someone thought it would be faster to do it here and then switch back
453 * to GDI32. I dunno. Write a test and let me know.
454 * A. It should be in here!
455 */
456
457 static const DWORD ROP3Table[256] =
458 {
459 0x000042, 0x010289, 0x020C89, 0x0300AA, 0x040C88, 0x0500A9, 0x060865, 0x0702C5,
460 0x080F08, 0x090245, 0x0A0329, 0x0B0B2A, 0x0C0324, 0x0D0B25, 0x0E08A5, 0x0F0001,
461 0x100C85, 0x1100A6, 0x120868, 0x1302C8, 0x140869, 0x1502C9, 0x165CCA, 0x171D54,
462 0x180D59, 0x191CC8, 0x1A06C5, 0x1B0768, 0x1C06CA, 0x1D0766, 0x1E01A5, 0x1F0385,
463 0x200F09, 0x210248, 0x220326, 0x230B24, 0x240D55, 0x251CC5, 0x2606C8, 0x271868,
464 0x280369, 0x2916CA, 0x2A0CC9, 0x2B1D58, 0x2C0784, 0x2D060A, 0x2E064A, 0x2F0E2A,
465 0x30032A, 0x310B28, 0x320688, 0x330008, 0x3406C4, 0x351864, 0x3601A8, 0x370388,
466 0x38078A, 0x390604, 0x3A0644, 0x3B0E24, 0x3C004A, 0x3D18A4, 0x3E1B24, 0x3F00EA,
467 0x400F0A, 0x410249, 0x420D5D, 0x431CC4, 0x440328, 0x450B29, 0x4606C6, 0x47076A,
468 0x480368, 0x4916C5, 0x4A0789, 0x4B0605, 0x4C0CC8, 0x4D1954, 0x4E0645, 0x4F0E25,
469 0x500325, 0x510B26, 0x5206C9, 0x530764, 0x5408A9, 0x550009, 0x5601A9, 0x570389,
470 0x580785, 0x590609, 0x5A0049, 0x5B18A9, 0x5C0649, 0x5D0E29, 0x5E1B29, 0x5F00E9,
471 0x600365, 0x6116C6, 0x620786, 0x630608, 0x640788, 0x650606, 0x660046, 0x6718A8,
472 0x6858A6, 0x690145, 0x6A01E9, 0x6B178A, 0x6C01E8, 0x6D1785, 0x6E1E28, 0x6F0C65,
473 0x700CC5, 0x711D5C, 0x720648, 0x730E28, 0x740646, 0x750E26, 0x761B28, 0x7700E6,
474 0x7801E5, 0x791786, 0x7A1E29, 0x7B0C68, 0x7C1E24, 0x7D0C69, 0x7E0955, 0x7F03C9,
475 0x8003E9, 0x810975, 0x820C49, 0x831E04, 0x840C48, 0x851E05, 0x8617A6, 0x8701C5,
476 0x8800C6, 0x891B08, 0x8A0E06, 0x8B0666, 0x8C0E08, 0x8D0668, 0x8E1D7C, 0x8F0CE5,
477 0x900C45, 0x911E08, 0x9217A9, 0x9301C4, 0x9417AA, 0x9501C9, 0x960169, 0x97588A,
478 0x981888, 0x990066, 0x9A0709, 0x9B07A8, 0x9C0704, 0x9D07A6, 0x9E16E6, 0x9F0345,
479 0xA000C9, 0xA11B05, 0xA20E09, 0xA30669, 0xA41885, 0xA50065, 0xA60706, 0xA707A5,
480 0xA803A9, 0xA90189, 0xAA0029, 0xAB0889, 0xAC0744, 0xAD06E9, 0xAE0B06, 0xAF0229,
481 0xB00E05, 0xB10665, 0xB21974, 0xB30CE8, 0xB4070A, 0xB507A9, 0xB616E9, 0xB70348,
482 0xB8074A, 0xB906E6, 0xBA0B09, 0xBB0226, 0xBC1CE4, 0xBD0D7D, 0xBE0269, 0xBF08C9,
483 0xC000CA, 0xC11B04, 0xC21884, 0xC3006A, 0xC40E04, 0xC50664, 0xC60708, 0xC707AA,
484 0xC803A8, 0xC90184, 0xCA0749, 0xCB06E4, 0xCC0020, 0xCD0888, 0xCE0B08, 0xCF0224,
485 0xD00E0A, 0xD1066A, 0xD20705, 0xD307A4, 0xD41D78, 0xD50CE9, 0xD616EA, 0xD70349,
486 0xD80745, 0xD906E8, 0xDA1CE9, 0xDB0D75, 0xDC0B04, 0xDD0228, 0xDE0268, 0xDF08C8,
487 0xE003A5, 0xE10185, 0xE20746, 0xE306EA, 0xE40748, 0xE506E5, 0xE61CE8, 0xE70D79,
488 0xE81D74, 0xE95CE6, 0xEA02E9, 0xEB0849, 0xEC02E8, 0xED0848, 0xEE0086, 0xEF0A08,
489 0xF00021, 0xF10885, 0xF20B05, 0xF3022A, 0xF40B0A, 0xF50225, 0xF60265, 0xF708C5,
490 0xF802E5, 0xF90845, 0xFA0089, 0xFB0A09, 0xFC008A, 0xFD0A0A, 0xFE02A9, 0xFF0062,
491 };
492
493 static __inline BYTE
494 SwapROP3_SrcDst(BYTE bRop3)
495 {
496 return (bRop3 & 0x99) | ((bRop3 & 0x22) << 1) | ((bRop3 & 0x44) >> 1);
497 }
498
499 #define FRGND_ROP3(ROP4) ((ROP4) & 0x00FFFFFF)
500 #define BKGND_ROP3(ROP4) (ROP3Table[(SwapROP3_SrcDst((ROP4)>>24)) & 0xFF])
501 #define DSTCOPY 0x00AA0029
502 #define DSTERASE 0x00220326 /* dest = dest & (~src) : DSna */
503
504 /* NOTE: An alternative algorithm could use a pattern brush, created from
505 * the mask bitmap and then use raster operation 0xCA to combine the fore
506 * and background bitmaps. In this case erasing the bits beforehand would be
507 * unneccessary. On the other hand the Operation does not provide an optimized
508 * version in the DIB code, while SRCAND and SRCPAINT do.
509 * A fully correct implementation would call Eng/DrvBitBlt, but our
510 * EngBitBlt completely ignores the mask surface.
511 *
512 * Msk Fg Bk => x
513 * P S D DPSDxax
514 * ------------------------------------------
515 * 0 0 0 0 0000xax = 000ax = 00x = 0
516 * 0 0 1 1 1001xax = 101ax = 10x = 1
517 * 0 1 0 0 0010xax = 001ax = 00x = 0
518 * 0 1 1 1 1011xax = 100ax = 10x = 1
519 * 1 0 0 0 0100xax = 010ax = 00x = 0
520 * 1 0 1 0 1101xax = 111ax = 11x = 0
521 * 1 1 0 1 0110xax = 011ax = 01x = 1
522 * 1 1 1 1 1111xax = 110ax = 10x = 1
523 *
524 * Operation index = 11001010 = 0xCA = PSaDPnao = DPSDxax
525 * ^ no, this is not random letters, its reverse Polish notation
526 */
527
528 BOOL APIENTRY
529 NtGdiMaskBlt(
530 HDC hdcDest,
531 INT nXDest,
532 INT nYDest,
533 INT nWidth,
534 INT nHeight,
535 HDC hdcSrc,
536 INT nXSrc,
537 INT nYSrc,
538 HBITMAP hbmMask,
539 INT xMask,
540 INT yMask,
541 DWORD dwRop,
542 IN DWORD crBackColor)
543 {
544 HBITMAP hbmFore, hbmBack;
545 HDC hdcMask, hdcFore, hdcBack;
546 PDC pdc;
547 HBRUSH hbr;
548 COLORREF crFore, crBack;
549
550 if (!hbmMask)
551 return NtGdiBitBlt(hdcDest,
552 nXDest,
553 nYDest,
554 nWidth,
555 nHeight,
556 hdcSrc,
557 nXSrc,
558 nYSrc,
559 FRGND_ROP3(dwRop),
560 crBackColor,
561 0);
562
563 /* Lock the dest DC */
564 pdc = DC_LockDc(hdcDest);
565 if (!pdc) return FALSE;
566
567 /* Get brush and colors from dest dc */
568 hbr = pdc->pdcattr->hbrush;
569 crFore = pdc->pdcattr->crForegroundClr;
570 crBack = pdc->pdcattr->crBackgroundClr;
571
572 /* Unlock the DC */
573 DC_UnlockDc(pdc);
574
575 /* 1. Create mask bitmap's dc */
576 hdcMask = NtGdiCreateCompatibleDC(hdcDest);
577 NtGdiSelectBitmap(hdcMask, hbmMask);
578
579 /* 2. Create masked Background bitmap */
580
581 /* 2.1 Create bitmap */
582 hdcBack = NtGdiCreateCompatibleDC(hdcDest);
583 hbmBack = NtGdiCreateCompatibleBitmap(hdcDest, nWidth, nHeight);
584 NtGdiSelectBitmap(hdcBack, hbmBack);
585
586 /* 2.2 Copy source bitmap */
587 NtGdiSelectBrush(hdcBack, hbr);
588 IntGdiSetBkColor(hdcBack, crBack);
589 IntGdiSetTextColor(hdcBack, crFore);
590 NtGdiBitBlt(hdcBack, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, SRCCOPY, 0, 0);
591
592 /* 2.3 Do the background rop */
593 NtGdiBitBlt(hdcBack, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, BKGND_ROP3(dwRop), 0, 0);
594
595 /* 2.4 Erase the foreground pixels */
596 IntGdiSetBkColor(hdcBack, 0xffffffff);
597 IntGdiSetTextColor(hdcBack, 0);
598 NtGdiBitBlt(hdcBack, 0, 0, nWidth, nHeight, hdcMask, xMask, yMask, SRCAND, 0, 0);
599
600 /* 3. Create masked Foreground bitmap */
601
602 /* 3.1 Create bitmap */
603 hdcFore = NtGdiCreateCompatibleDC(hdcDest);
604 hbmFore = NtGdiCreateCompatibleBitmap(hdcDest, nWidth, nHeight);
605 NtGdiSelectBitmap(hdcFore, hbmFore);
606
607 /* 3.2 Copy the dest bitmap */
608 NtGdiSelectBrush(hdcFore, hbr);
609 IntGdiSetBkColor(hdcFore, crBack);
610 IntGdiSetTextColor(hdcFore, crFore);
611 NtGdiBitBlt(hdcFore, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY, 0, 0);
612
613 /* 2.3 Do the foreground rop */
614 NtGdiBitBlt(hdcFore, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop), 0,0);
615
616 /* 2.4 Erase the background pixels */
617 IntGdiSetBkColor(hdcFore, 0);
618 IntGdiSetTextColor(hdcFore, 0xffffffff);
619 NtGdiBitBlt(hdcFore, 0, 0, nWidth, nHeight, hdcMask, xMask, yMask, SRCAND, 0, 0);
620
621 /* 3. Combine the fore and background into the background bitmap */
622 NtGdiBitBlt(hdcBack, 0, 0, nWidth, nHeight, hdcFore, 0, 0, SRCPAINT, 0, 0);
623
624 /* 4. Copy the result to hdcDest */
625 NtGdiBitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcBack, 0, 0, SRCCOPY, 0, 0);
626
627 /* 5. delete all temp objects */
628 NtGdiDeleteObjectApp(hdcBack);
629 NtGdiDeleteObjectApp(hdcFore);
630 NtGdiDeleteObjectApp(hdcMask);
631 GreDeleteObject(hbmFore);
632 GreDeleteObject(hbmBack);
633
634 return TRUE;
635 }
636
637 BOOL
638 APIENTRY
639 NtGdiPlgBlt(
640 IN HDC hdcTrg,
641 IN LPPOINT pptlTrg,
642 IN HDC hdcSrc,
643 IN INT xSrc,
644 IN INT ySrc,
645 IN INT cxSrc,
646 IN INT cySrc,
647 IN HBITMAP hbmMask,
648 IN INT xMask,
649 IN INT yMask,
650 IN DWORD crBackColor)
651 {
652 UNIMPLEMENTED;
653 return FALSE;
654 }
655
656 BOOL APIENTRY
657 GreStretchBltMask(
658 HDC hDCDest,
659 INT XOriginDest,
660 INT YOriginDest,
661 INT WidthDest,
662 INT HeightDest,
663 HDC hDCSrc,
664 INT XOriginSrc,
665 INT YOriginSrc,
666 INT WidthSrc,
667 INT HeightSrc,
668 DWORD ROP,
669 IN DWORD dwBackColor,
670 HDC hDCMask,
671 INT XOriginMask,
672 INT YOriginMask)
673 {
674 PDC DCDest;
675 PDC DCSrc = NULL;
676 PDC DCMask = NULL;
677 PDC_ATTR pdcattr;
678 SURFACE *BitmapDest, *BitmapSrc = NULL;
679 SURFACE *BitmapMask = NULL;
680 RECTL DestRect;
681 RECTL SourceRect;
682 POINTL MaskPoint;
683 BOOL Status = FALSE;
684 EXLATEOBJ exlo;
685 XLATEOBJ *XlateObj = NULL;
686 POINTL BrushOrigin;
687 BOOL UsesSource = ROP3_USES_SOURCE(ROP);
688
689 if (0 == WidthDest || 0 == HeightDest || 0 == WidthSrc || 0 == HeightSrc)
690 {
691 SetLastWin32Error(ERROR_INVALID_PARAMETER);
692 return FALSE;
693 }
694
695 DCDest = DC_LockDc(hDCDest);
696 if (NULL == DCDest)
697 {
698 DPRINT1("Invalid destination dc handle (0x%08x) passed to NtGdiStretchBlt\n", hDCDest);
699 SetLastWin32Error(ERROR_INVALID_HANDLE);
700 return FALSE;
701 }
702
703 if (DCDest->dctype == DC_TYPE_INFO)
704 {
705 DC_UnlockDc(DCDest);
706 /* Yes, Windows really returns TRUE in this case */
707 return TRUE;
708 }
709
710 if (UsesSource)
711 {
712 if (hDCSrc != hDCDest)
713 {
714 DCSrc = DC_LockDc(hDCSrc);
715 if (NULL == DCSrc)
716 {
717 DC_UnlockDc(DCDest);
718 DPRINT1("Invalid source dc handle (0x%08x) passed to NtGdiStretchBlt\n", hDCSrc);
719 SetLastWin32Error(ERROR_INVALID_HANDLE);
720 return FALSE;
721 }
722 if (DCSrc->dctype == DC_TYPE_INFO)
723 {
724 DC_UnlockDc(DCSrc);
725 DC_UnlockDc(DCDest);
726 /* Yes, Windows really returns TRUE in this case */
727 return TRUE;
728 }
729 }
730 else
731 {
732 DCSrc = DCDest;
733 }
734 }
735
736 pdcattr = DCDest->pdcattr;
737
738 if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
739 DC_vUpdateFillBrush(DCDest);
740
741 DestRect.left = XOriginDest;
742 DestRect.top = YOriginDest;
743 DestRect.right = XOriginDest+WidthDest;
744 DestRect.bottom = YOriginDest+HeightDest;
745 IntLPtoDP(DCDest, (LPPOINT)&DestRect, 2);
746
747 DestRect.left += DCDest->ptlDCOrig.x;
748 DestRect.top += DCDest->ptlDCOrig.y;
749 DestRect.right += DCDest->ptlDCOrig.x;
750 DestRect.bottom += DCDest->ptlDCOrig.y;
751
752 SourceRect.left = XOriginSrc;
753 SourceRect.top = YOriginSrc;
754 SourceRect.right = XOriginSrc+WidthSrc;
755 SourceRect.bottom = YOriginSrc+HeightSrc;
756
757 if (UsesSource)
758 {
759 IntLPtoDP(DCSrc, (LPPOINT)&SourceRect, 2);
760
761 SourceRect.left += DCSrc->ptlDCOrig.x;
762 SourceRect.top += DCSrc->ptlDCOrig.y;
763 SourceRect.right += DCSrc->ptlDCOrig.x;
764 SourceRect.bottom += DCSrc->ptlDCOrig.y;
765 }
766
767 BrushOrigin.x = 0;
768 BrushOrigin.y = 0;
769
770 /* Determine surfaces to be used in the bitblt */
771 BitmapDest = DCDest->dclevel.pSurface;
772 if (BitmapDest == NULL)
773 goto failed;
774 if (UsesSource)
775 {
776 BitmapSrc = DCSrc->dclevel.pSurface;
777 if (BitmapSrc == NULL)
778 goto failed;
779
780 /* Create the XLATEOBJ. */
781 EXLATEOBJ_vInitXlateFromDCs(&exlo, DCSrc, DCDest);
782 XlateObj = &exlo.xlo;
783 }
784
785 /* Offset the brush */
786 BrushOrigin.x += DCDest->ptlDCOrig.x;
787 BrushOrigin.y += DCDest->ptlDCOrig.y;
788
789 /* Make mask surface for source surface */
790 if (BitmapSrc && hDCMask)
791 {
792 DCMask = DC_LockDc(hDCMask);
793 if (DCMask)
794 {
795 BitmapMask = DCMask->dclevel.pSurface;
796 if (BitmapMask &&
797 (BitmapMask->SurfObj.sizlBitmap.cx < WidthSrc ||
798 BitmapMask->SurfObj.sizlBitmap.cy < HeightSrc))
799 {
800 DPRINT1("%dx%d mask is smaller than %dx%d bitmap\n",
801 BitmapMask->SurfObj.sizlBitmap.cx, BitmapMask->SurfObj.sizlBitmap.cy,
802 WidthSrc, HeightSrc);
803 goto failed;
804 }
805 /* Create mask offset point */
806 MaskPoint.x = XOriginMask;
807 MaskPoint.y = YOriginMask;
808 IntLPtoDP(DCMask, &MaskPoint, 1);
809 MaskPoint.x += DCMask->ptlDCOrig.x;
810 MaskPoint.y += DCMask->ptlDCOrig.x;
811 }
812 }
813
814 /* Perform the bitblt operation */
815 Status = IntEngStretchBlt(&BitmapDest->SurfObj,
816 &BitmapSrc->SurfObj,
817 BitmapMask ? &BitmapMask->SurfObj : NULL,
818 DCDest->rosdc.CombinedClip,
819 XlateObj,
820 &DestRect,
821 &SourceRect,
822 BitmapMask ? &MaskPoint : NULL,
823 &DCDest->eboFill.BrushObject,
824 &BrushOrigin,
825 ROP3_TO_ROP4(ROP));
826
827 failed:
828 if (UsesSource)
829 {
830 EXLATEOBJ_vCleanup(&exlo);
831 }
832 if (UsesSource && hDCSrc != hDCDest)
833 {
834 DC_UnlockDc(DCSrc);
835 }
836 if (DCMask)
837 {
838 DC_UnlockDc(DCMask);
839 }
840 DC_UnlockDc(DCDest);
841
842 return Status;
843 }
844
845
846 BOOL APIENTRY
847 NtGdiStretchBlt(
848 HDC hDCDest,
849 INT XOriginDest,
850 INT YOriginDest,
851 INT WidthDest,
852 INT HeightDest,
853 HDC hDCSrc,
854 INT XOriginSrc,
855 INT YOriginSrc,
856 INT WidthSrc,
857 INT HeightSrc,
858 DWORD ROP,
859 IN DWORD dwBackColor)
860 {
861 return GreStretchBltMask(
862 hDCDest,
863 XOriginDest,
864 YOriginDest,
865 WidthDest,
866 HeightDest,
867 hDCSrc,
868 XOriginSrc,
869 YOriginSrc,
870 WidthSrc,
871 HeightSrc,
872 ROP,
873 dwBackColor,
874 NULL,
875 0,
876 0);
877 }
878
879
880 BOOL FASTCALL
881 IntPatBlt(
882 PDC pdc,
883 INT XLeft,
884 INT YLeft,
885 INT Width,
886 INT Height,
887 DWORD dwRop,
888 PBRUSH pbrush)
889 {
890 RECTL DestRect;
891 SURFACE *psurf;
892 EBRUSHOBJ eboFill;
893 POINTL BrushOrigin;
894 BOOL ret;
895
896 ASSERT(pbrush);
897
898 psurf = pdc->dclevel.pSurface;
899 if (psurf == NULL)
900 {
901 SetLastWin32Error(ERROR_INVALID_HANDLE);
902 return FALSE;
903 }
904
905 if (pbrush->flAttrs & GDIBRUSH_IS_NULL)
906 {
907 return TRUE;
908 }
909
910 if (Width > 0)
911 {
912 DestRect.left = XLeft;
913 DestRect.right = XLeft + Width;
914 }
915 else
916 {
917 DestRect.left = XLeft + Width + 1;
918 DestRect.right = XLeft + 1;
919 }
920
921 if (Height > 0)
922 {
923 DestRect.top = YLeft;
924 DestRect.bottom = YLeft + Height;
925 }
926 else
927 {
928 DestRect.top = YLeft + Height + 1;
929 DestRect.bottom = YLeft + 1;
930 }
931
932 IntLPtoDP(pdc, (LPPOINT)&DestRect, 2);
933
934 DestRect.left += pdc->ptlDCOrig.x;
935 DestRect.top += pdc->ptlDCOrig.y;
936 DestRect.right += pdc->ptlDCOrig.x;
937 DestRect.bottom += pdc->ptlDCOrig.y;
938
939 BrushOrigin.x = pbrush->ptOrigin.x + pdc->ptlDCOrig.x;
940 BrushOrigin.y = pbrush->ptOrigin.y + pdc->ptlDCOrig.y;
941
942 EBRUSHOBJ_vInit(&eboFill, pbrush, pdc);
943
944 ret = IntEngBitBlt(
945 &psurf->SurfObj,
946 NULL,
947 NULL,
948 pdc->rosdc.CombinedClip,
949 NULL,
950 &DestRect,
951 NULL,
952 NULL,
953 &eboFill.BrushObject, // use pDC->eboFill
954 &BrushOrigin,
955 ROP3_TO_ROP4(dwRop));
956
957 EBRUSHOBJ_vCleanup(&eboFill);
958
959 return ret;
960 }
961
962 BOOL FASTCALL
963 IntGdiPolyPatBlt(
964 HDC hDC,
965 DWORD dwRop,
966 PPATRECT pRects,
967 INT cRects,
968 ULONG Reserved)
969 {
970 INT i;
971 PBRUSH pbrush;
972 PDC pdc;
973
974 pdc = DC_LockDc(hDC);
975 if (!pdc)
976 {
977 SetLastWin32Error(ERROR_INVALID_HANDLE);
978 return FALSE;
979 }
980
981 if (pdc->dctype == DC_TYPE_INFO)
982 {
983 DC_UnlockDc(pdc);
984 /* Yes, Windows really returns TRUE in this case */
985 return TRUE;
986 }
987
988 for (i = 0; i < cRects; i++)
989 {
990 pbrush = BRUSH_LockBrush(pRects->hBrush);
991 if(pbrush != NULL)
992 {
993 IntPatBlt(
994 pdc,
995 pRects->r.left,
996 pRects->r.top,
997 pRects->r.right,
998 pRects->r.bottom,
999 dwRop,
1000 pbrush);
1001 BRUSH_UnlockBrush(pbrush);
1002 }
1003 pRects++;
1004 }
1005
1006 DC_UnlockDc(pdc);
1007
1008 return TRUE;
1009 }
1010
1011
1012 BOOL APIENTRY
1013 NtGdiPatBlt(
1014 HDC hDC,
1015 INT XLeft,
1016 INT YLeft,
1017 INT Width,
1018 INT Height,
1019 DWORD ROP)
1020 {
1021 PBRUSH pbrush;
1022 DC *dc;
1023 PDC_ATTR pdcattr;
1024 BOOL ret;
1025
1026 BOOL UsesSource = ROP3_USES_SOURCE(ROP);
1027 if (UsesSource)
1028 {
1029 /* in this case we call on GdiMaskBlt */
1030 return NtGdiMaskBlt(hDC, XLeft, YLeft, Width, Height, 0,0,0,0,0,0,ROP,0);
1031 }
1032
1033 dc = DC_LockDc(hDC);
1034 if (dc == NULL)
1035 {
1036 SetLastWin32Error(ERROR_INVALID_HANDLE);
1037 return FALSE;
1038 }
1039 if (dc->dctype == DC_TYPE_INFO)
1040 {
1041 DC_UnlockDc(dc);
1042 /* Yes, Windows really returns TRUE in this case */
1043 return TRUE;
1044 }
1045
1046 pdcattr = dc->pdcattr;
1047
1048 if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
1049 DC_vUpdateFillBrush(dc);
1050
1051 pbrush = BRUSH_LockBrush(pdcattr->hbrush);
1052 if (pbrush == NULL)
1053 {
1054 SetLastWin32Error(ERROR_INVALID_HANDLE);
1055 DC_UnlockDc(dc);
1056 return FALSE;
1057 }
1058
1059 ret = IntPatBlt(dc, XLeft, YLeft, Width, Height, ROP, pbrush);
1060
1061 BRUSH_UnlockBrush(pbrush);
1062 DC_UnlockDc(dc);
1063
1064 return ret;
1065 }
1066
1067 BOOL APIENTRY
1068 NtGdiPolyPatBlt(
1069 HDC hDC,
1070 DWORD dwRop,
1071 IN PPOLYPATBLT pRects,
1072 IN DWORD cRects,
1073 IN DWORD Mode)
1074 {
1075 PPATRECT rb = NULL;
1076 NTSTATUS Status = STATUS_SUCCESS;
1077 BOOL Ret;
1078
1079 if (cRects > 0)
1080 {
1081 rb = ExAllocatePoolWithTag(PagedPool, sizeof(PATRECT) * cRects, TAG_PATBLT);
1082 if (!rb)
1083 {
1084 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
1085 return FALSE;
1086 }
1087 _SEH2_TRY
1088 {
1089 ProbeForRead(pRects,
1090 cRects * sizeof(PATRECT),
1091 1);
1092 RtlCopyMemory(rb,
1093 pRects,
1094 cRects * sizeof(PATRECT));
1095 }
1096 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1097 {
1098 Status = _SEH2_GetExceptionCode();
1099 }
1100 _SEH2_END;
1101
1102 if (!NT_SUCCESS(Status))
1103 {
1104 ExFreePoolWithTag(rb, TAG_PATBLT);
1105 SetLastNtError(Status);
1106 return FALSE;
1107 }
1108 }
1109
1110 Ret = IntGdiPolyPatBlt(hDC, dwRop, rb, cRects, Mode);
1111
1112 if (cRects > 0)
1113 ExFreePoolWithTag(rb, TAG_PATBLT);
1114
1115 return Ret;
1116 }