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